@mthanh/vespercli 1.4.0 → 1.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/README.md CHANGED
@@ -170,6 +170,25 @@ vespercli reset --local-only # Only remove local `.vesper/` folder
170
170
  vespercli reset --full # Remove EVERYTHING including vesper.agent.md (requires typing "YES")
171
171
  ```
172
172
 
173
+ ### `vespercli mcp`
174
+
175
+ Manage MCP servers for whichever target(s) are installed here — Copilot (`.vscode/mcp.json`), Claude Code (`.mcp.json`), or both at once. `mcp add`/`mcp remove`/`mcp list` are for **optional catalog servers** (e.g. `clickup`); the three Vesper-core servers (`vesper-indexing`, `sequential-thinking`, `memory`) are managed separately via `mcp enable`/`mcp disable`/`mcp sync` and are never addable/removable through `mcp add`/`mcp remove`.
176
+
177
+ ```bash
178
+ vespercli mcp # Show MCP server status for the installed target(s)
179
+ vespercli mcp status --target claude # Status for Claude Code only; also warns if .mcp.json has drifted from .vesperrc tracking
180
+ vespercli mcp list # List catalog + custom servers, and which are installed
181
+ vespercli mcp add clickup # Add a catalog server (writes both .vscode/mcp.json and .mcp.json in a dual-target workspace)
182
+ vespercli mcp add clickup --target claude # Add for Claude Code only — writes .mcp.json (env values rewritten to Claude's ${VAR} form) and records it in .vesperrc
183
+ vespercli mcp remove clickup # Remove a catalog server (mirrors add's target resolution)
184
+ vespercli mcp enable # Enable the core vesper-indexing server
185
+ vespercli mcp disable # Disable it
186
+ vespercli mcp sync # Re-sync tool auto-approval (Copilot) / refresh config (Claude)
187
+ vespercli mcp reindex --full # Clear and rebuild the shared code index
188
+ ```
189
+
190
+ `mcp add`/`mcp remove`/`mcp list` are fully supported for the Claude Code target — earlier versions silently no-op'd here for anything beyond the 3 core servers.
191
+
173
192
  ### `vespercli --version`
174
193
 
175
194
  Display the current version.
@@ -233,7 +252,10 @@ vespercli add agents code-reviewer --target claude # Add one subagent to t
233
252
  vespercli list --target claude # See what's installed
234
253
  vespercli update --target claude # Refresh the plugin + orchestrator playbook after `npm update`
235
254
  vespercli reset --target claude # Remove this project's files (leaves the shared plugin catalog alone)
236
- vespercli mcp status --target claude # Check the vesper-indexing MCP server in .mcp.json
255
+ vespercli mcp status --target claude # Check the vesper-indexing MCP server in .mcp.json; also warns on .mcp.json vs .vesperrc drift
256
+ vespercli mcp add clickup --target claude # Add an optional catalog MCP server to .mcp.json + record it in .vesperrc
257
+ vespercli mcp remove clickup --target claude # Remove it (prunes both .mcp.json and .vesperrc)
258
+ vespercli mcp list --target claude # List catalog + custom servers configured for this target
237
259
  ```
238
260
 
239
261
  Unlike the Copilot target, this one has **no editor dependency** — `~/.claude/...` and a project's `.claude/`/`CLAUDE.md`/`.mcp.json` are read by the Claude Code engine itself, so the same install works whether you drive it from the plain terminal CLI, the VS Code extension, JetBrains, or the desktop app.
@@ -2,7 +2,7 @@
2
2
  name: feature-wrap-document
3
3
  description: Knowledge curator that captures implementation patterns and updates documentation, skills, and context
4
4
  model: claude-sonnet-5
5
- tools: Read, Grep, Glob, Edit, Write, Agent, mcp__vesper-indexing__vesper_search, mcp__memory__create_entities, mcp__memory__create_relations, mcp__memory__add_observations
5
+ tools: Read, Grep, Glob, Edit, Write, Agent, mcp__vesper-indexing__vesper_search, mcp__memory__create_entities, mcp__memory__create_relations, mcp__memory__add_observations, mcp__memory__search_nodes, mcp__memory__open_nodes, mcp__memory__delete_entities, mcp__memory__delete_observations
6
6
  skills: [agent-fundamentals]
7
7
  ---
8
8
 
@@ -550,3 +550,15 @@ When invoked, you WILL:
550
550
  7. **Summarize** all completed updates with file links
551
551
 
552
552
  Your goal is to ensure **every implementation teaches the next one** by systematically capturing and organizing knowledge.
553
+
554
+ ## 🗜️ Memory Compaction Mode (`/compact-knowledge` only — never the default behavior)
555
+
556
+ A **separate, explicitly-invoked mode**, distinct from your normal per-task memory-update job above. Runs when Vesper delegates a knowledge-compaction request (triggered by `/compact-knowledge`, or a memory-size/entity-count threshold suggestion the user accepted). `history-logger` handles the `history.md`/tracking-archive side of the same request in parallel — this mode is scoped to the memory graph only.
557
+
558
+ 1. `read_graph()` (or `search_nodes` broadly) to see the full set of entities.
559
+ 2. Identify **stale, observation-heavy entities** — those tied to stories/tasks already in `.vesper/.tracking/stories/completed/` with no observations added recently and no `current_task`/active relation pointing at them. Never touch an entity named `current_task` or anything with an active relation.
560
+ 3. For each stale entity: merge its observations into a single summarized entity per topic/category (e.g. collapse five separate `learning_flow_*` entities about the same recurring pattern into one, keeping the clearest/most complete observation and dropping exact duplicates) — use `add_observations` on a consolidated entity and `delete_entities` for the ones folded in. Preserve `supersedes` relations so history isn't lost, just compacted.
561
+ 4. Never delete a `preference` or `workspace_pattern` entity outright — these tend to stay relevant; only dedupe near-identical ones.
562
+ 5. Report: entity count before/after, and a short list of what was merged.
563
+
564
+ **Never** perform this compaction as a side effect of a normal feature-wrap invocation — only when explicitly asked for compaction.
@@ -52,3 +52,29 @@ When asked to log something (e.g., "Log that Phase 1 started"), generate the for
52
52
  - **Do Not Overwrite**: NEVER use write/overwrite mode. ALWAYS use append logic (read file -> append text -> write back).
53
53
  - **No Fluff**: Do not add conversational filler.
54
54
  - **Accuracy**: The timestamp must be accurate to the minute.
55
+
56
+ ## 🗜️ Compaction Mode (`/compact-knowledge` only — never the default behavior)
57
+
58
+ This is a **separate, explicitly-invoked mode** — distinct from your normal append-only scribe job above. It only runs when Vesper delegates a knowledge-compaction request (triggered by `/compact-knowledge`, or a memory/history-size threshold suggestion the user accepted).
59
+
60
+ **Goal**: keep `.vesper/history.md` and `.vesper/.tracking/stories/completed/` small enough that a fresh session doesn't have to ingest a huge file/tree just to get oriented — without losing the record (everything moves to an archive, nothing is deleted).
61
+
62
+ ### 1. Rotate `.vesper/history.md`
63
+
64
+ 1. Read the full file. Determine the cutoff: everything **before** the last N entries (default N=30, or as specified by the delegating request) is "old."
65
+ 2. If there's nothing old enough to rotate (file is already short), report that and stop — do not rotate a short file just because you were asked.
66
+ 3. For the old portion, write **one digest line per rotated batch** summarizing what happened (dates covered, count of entries, one-line theme per distinct task/phase you can identify) — this is the one place in this mode where summarization is expected of you, unlike your normal logging job.
67
+ 4. Append the **verbatim old entries** (unmodified) to `.vesper/history-archive/YYYYMM.md` (month of the oldest rotated entry; create the file with a `# Vesper History Archive — YYYY-MM` header if it doesn't exist), using `Edit`.
68
+ 5. Rewrite `.vesper/history.md` to contain: the original header, the new digest line(s) referencing the archive file, then the last N entries verbatim (unchanged).
69
+
70
+ ### 2. Archive completed tracking stories
71
+
72
+ 1. List `.vesper/.tracking/stories/completed/`. For story files older than N days (default 30, or as specified), move them (via `Bash mv`, not delete) into `.vesper/.tracking/stories/completed/archive/YYYYMM/`, grouped by the month they were completed.
73
+ 2. Never touch `refining/`, `backlog/`, `inprogress/`, or `inreview/` — only `completed/`.
74
+ 3. Report the count moved and where.
75
+
76
+ ### Constraints (Compaction Mode only)
77
+
78
+ - **Never delete** — every rotation/archive is a move, not a removal.
79
+ - **Never touch active state** — anything in `.tracking/stories/` outside `completed/`, and the most recent N `history.md` entries, are off-limits.
80
+ - **Report what moved**: file counts and destination paths, so the user/orchestrator can verify nothing active was swept up.
@@ -247,8 +247,9 @@ After Phase 3 is complete, ensure the Vesper specialist catalog is installed at
247
247
 
248
248
  Before assuming any subagent is available, check whether `~/.claude/skills/vesper/` (or the plugin path recorded in this project's `.vesperrc.claude.pluginPath`) exists.
249
249
 
250
- - **If it exists**: The catalog is already installed. Proceed to Step 1.
250
+ - **If it exists AND this is NOT an explicit re-initialization request**: The catalog is already installed. Proceed to Step 1.
251
251
  - **If it does NOT exist**: Run `vesper init --force-default --target claude` via `Bash` to install it. Then proceed to Step 1.
252
+ - **If this IS an explicit re-initialization request** (catalog already exists): still run `vesper init --force-default --target claude` before proceeding. It's idempotent — this refreshes project-level local config (`.mcp.json`, the `.gitignore` guard block, git hooks) to the current CLI version without touching anything you own (context, orchestration, tracking). Then proceed to Step 1.
252
253
 
253
254
  #### Step 1 — Get Available Subagents
254
255
 
@@ -0,0 +1,10 @@
1
+ ---
2
+ description: Compact persisted Vesper knowledge (history.md, memory.jsonl, completed tracking stories) so a fresh session doesn't have to ingest all of it — distinct from Claude Code's own /compact, which only summarizes the current context window.
3
+ ---
4
+
5
+ Compact persisted Vesper knowledge. Delegate in parallel:
6
+
7
+ 1. `history-logger` in Compaction Mode: rotate `.vesper/history.md` (archive entries older than the last 30 into `.vesper/history-archive/YYYYMM.md`) and archive `.vesper/.tracking/stories/completed/` entries older than 30 days.
8
+ 2. `feature-wrap-document` in Memory Compaction Mode: merge/dedupe stale entities in the MCP memory graph, never touching `current_task` or active entities.
9
+
10
+ Report what was archived/merged from both. Nothing is deleted — only moved to archive files or consolidated within the memory graph.
@@ -6,6 +6,12 @@ description: 'Vesper orchestration data — team roster, task management, routin
6
6
 
7
7
  **Source of truth**: this file is the single authority for this project's available specialist subagents, their roles, and their skill assignments. The orchestrator playbook (`vesper-orchestrator.md`, imported above this file in root `CLAUDE.md`) routes purely by the names listed in the **Team Roster** below.
8
8
 
9
+ ## Repository Policy
10
+
11
+ Base branch: `<!-- workspace-learner: fill in with the repo's actual default branch, e.g. via `git symbolic-ref refs/remotes/origin/HEAD` or `git branch --show-current` if no remote yet -->`
12
+
13
+ Every git worktree for this project is created **from the base branch above** — never from another worktree's branch. `.vesper/.tracking/`, `.vesper/history.md`, and `.vesper/memory.jsonl` are git-tracked and shared by every AI client working this workspace (see the `mcp-memory` skill and the merge-driver setup in `.gitattributes`) — never create a client-specific tracking folder. `.mcp.json`, `.vscode/mcp.json`, `.vesperrc`, and `.vesper/index.db` are local/gitignored and get regenerated automatically for each worktree (SessionStart hook, VS Code folder-open task, and `git post-checkout` hook all call `vespercli worktree bootstrap`).
14
+
9
15
  ## Task Management
10
16
 
11
17
  System: Local
@@ -169,6 +169,23 @@ When workspace is already set up:
169
169
 
170
170
  ---
171
171
 
172
+ ## 🔌 MCP Readiness Preflight
173
+
174
+ Before the first delegation of a session (not on every turn — once state is confirmed, don't re-check), verify every MCP server this project declares is actually reachable, not just configured. This project's `.mcp.json` declares `vesper-indexing`, `sequential-thinking`, `memory`, plus any project-added servers (`vespercli mcp list`).
175
+
176
+ **Check**: run `vespercli mcp status --target claude` in terminal. This reuses the same status logic `vespercli mcp status` already uses for reporting — no new tool needed.
177
+
178
+ | Result | Action |
179
+ | :--- | :--- |
180
+ | All declared servers configured and the index/server artifacts exist | Proceed normally |
181
+ | A server is configured but its underlying process/tool isn't responding (e.g. a `vesper_search` call errors, memory tools are unavailable) | Tell the user which server is down and that a session reload may be needed. Do NOT silently route around a missing required MCP tool. |
182
+ | `.mcp.json` itself looks stale/missing for this worktree (fresh worktree, never bootstrapped) | Run `vespercli worktree bootstrap --quiet` once, then re-check. This is the same idempotent step the SessionStart hook already runs — safe to re-run here if it somehow hasn't fired yet. |
183
+ | `vespercli mcp status --target claude` reports **MCP config drift** — a non-core server is live in `.mcp.json` but absent from `.vesperrc mcp.servers` | Non-blocking staleness signal: tracking and the generated docs are out of sync with the live config. Suggest the user run `/reinit` (or re-run `workspace-learner`) to resync `.vesperrc` and the generated docs. Do NOT auto-fix — it is a read-only diff. |
184
+
185
+ This is a readiness gate, not a blocker on every message — once confirmed for the session, don't re-run it before every delegation. The existing reactive rule ("if `vesper-indexing` is unavailable, STOP and ask") still applies mid-session if a server drops out later.
186
+
187
+ ---
188
+
172
189
  ## 🎯 Purpose Router
173
190
 
174
191
  ### Pre-Check: New-Task Detection (context hygiene)
@@ -201,6 +218,8 @@ Then **classify and route the new task as normal** — do not block on it. `/com
201
218
 
202
219
  **Bias**: when relatedness is ambiguous, treat it as a continuation and stay quiet. A needless `/compact` nag is more annoying than a slightly fuller context window, and the Resumption protocol can always rebuild state from disk regardless.
203
220
 
221
+ **Sibling suggestion — persisted knowledge, not context window**: `/compact` only summarizes *this conversation's* context window. It doesn't shrink what's on disk. At the same new-task detection point, if `.vesper/memory.jsonl` looks large (roughly >500 entities, or the file is large enough that a `read_graph` response feels unwieldy) or `.vesper/history.md` has grown long (roughly >150 entries), separately suggest `/compact-knowledge` — a different, non-destructive workflow that rotates old history into an archive file and merges stale memory entities, so a *future* session doesn't have to ingest all of it. These two suggestions are independent: don't conflate them, and don't block on either.
222
+
204
223
  ### Classify the request
205
224
 
206
225
  Classify every user request into exactly one purpose:
@@ -592,6 +611,8 @@ For every multi-step purpose pipeline:
592
611
  - **Started log** must contain: Goal + Assigned Agent (enough to resume if interrupted)
593
612
  - When delegating to `history-logger`, include your own model/session identity as the Author (e.g., `"Log that Phase 1 started. Author: Claude Sonnet 5."`) — useful given this workspace's tracking state may be shared with a Copilot session (see cross-client resumption note above); `history-logger` itself doesn't need to know why, it just places whatever value you give it
594
613
  - **Memory update**: After Implementation or Testing completes, `feature-wrap-document` captures learnings via the MCP memory server — see the `mcp-memory` skill
614
+ - **Commit hygiene**: `vesper init`/reinit installs a `pre-commit` git hook that auto-includes any dirty team-roster/context/history/`.tracking`/memory files into a commit that touches other work — this is what guarantees those files are never left out of a commit or PR, regardless of whether a human or an agent runs `git commit`. No pipeline step needs to commit these files itself; the hook covers it whenever a commit actually happens. Pushing remains a separate, always-confirmed action — the hook only affects what rides along inside a commit, never when/whether to push.
615
+ - **Cross-worktree merges**: `.vesper/history.md` and `.vesper/memory.jsonl` have git merge drivers configured (`.gitattributes`, set up by `vesper init`) that resolve automatically — union for history, entity-aware merge for memory — so parallel worktrees converging on the base branch normally need no manual resolution for either file. `.claude/vesper/orchestration.md` and `.claude/vesper/context.md` are structured markdown with no automatic merge driver; if git reports a real conflict in either, do NOT hand-resolve the markdown diff yourself — delegate to `workspace-learner` with both conflicting versions (the working-tree conflicted file, or `git show :2:<path>`/`:3:<path>` for the two sides) and ask it to reconcile them, since it already owns regenerating these files.
595
616
 
596
617
  ### Resumption
597
618
 
@@ -550,6 +550,18 @@ When invoked, you WILL:
550
550
 
551
551
  Your goal is to ensure **every implementation teaches the next one** by systematically capturing and organizing knowledge.
552
552
 
553
+ ## 🗜️ Memory Compaction Mode (`/compact-knowledge` only — never the default behavior)
554
+
555
+ A **separate, explicitly-invoked mode**, distinct from your normal per-task memory-update job above. Runs when Vesper delegates a knowledge-compaction request (triggered by `/compact-knowledge`, or a memory-size/entity-count threshold suggestion the user accepted). `@History Logger` handles the `history.md`/tracking-archive side of the same request in parallel — this mode is scoped to the memory graph only.
556
+
557
+ 1. `read_graph()` (or `search_nodes` broadly) to see the full set of entities.
558
+ 2. Identify **stale, observation-heavy entities** — those tied to stories/tasks already in `.vesper/.tracking/stories/completed/` with no observations added recently and no `current_task`/active relation pointing at them. Never touch an entity named `current_task` or anything with an active relation.
559
+ 3. For each stale entity: merge its observations into a single summarized entity per topic/category (e.g. collapse five separate `learning_flow_*` entities about the same recurring pattern into one, keeping the clearest/most complete observation and dropping exact duplicates) — use `add_observations` on a consolidated entity and `delete_entities` for the ones folded in. Preserve `supersedes` relations so history isn't lost, just compacted.
560
+ 4. Never delete a `preference` or `workspace_pattern` entity outright — these tend to stay relevant; only dedupe near-identical ones.
561
+ 5. Report: entity count before/after, and a short list of what was merged.
562
+
563
+ **Never** perform this compaction as a side effect of a normal feature-wrap invocation — only when explicitly asked for compaction.
564
+
553
565
  ## Terminal Discipline
554
566
 
555
567
  - **Tools-first, terminal-last**: Never use terminal for tasks built-in tools handle (`read_file`, `grep_search`, `file_search`, `create_file`, `replace_string_in_file`). Never use `python -c`, `node -e`, or shell commands to read, write, or modify files.
@@ -54,6 +54,32 @@ When asked to log something (e.g., "Log that Phase 1 started"), generate the for
54
54
  - **No Fluff**: Do not add conversational filler.
55
55
  - **Accuracy**: The timestamp must be accurate to the minute.
56
56
 
57
+ ## 🗜️ Compaction Mode (`/compact-knowledge` only — never the default behavior)
58
+
59
+ This is a **separate, explicitly-invoked mode** — distinct from your normal append-only scribe job above. It only runs when Vesper delegates a knowledge-compaction request (triggered by `/compact-knowledge` or its Copilot equivalent, or a memory/history-size threshold suggestion the user accepted).
60
+
61
+ **Goal**: keep `.vesper/history.md` and `.vesper/.tracking/stories/completed/` small enough that a fresh session doesn't have to ingest a huge file/tree just to get oriented — without losing the record (everything moves to an archive, nothing is deleted).
62
+
63
+ ### 1. Rotate `.vesper/history.md`
64
+
65
+ 1. Read the full file. Determine the cutoff: everything **before** the last N entries (default N=30, or as specified by the delegating request) is "old."
66
+ 2. If there's nothing old enough to rotate (file is already short), report that and stop — do not rotate a short file just because you were asked.
67
+ 3. For the old portion, write **one digest line per rotated batch** summarizing what happened (dates covered, count of entries, one-line theme per distinct task/phase you can identify) — this is the one place in this mode where summarization is expected of you, unlike your normal logging job.
68
+ 4. Append the **verbatim old entries** (unmodified) to `.vesper/history-archive/YYYYMM.md` (month of the oldest rotated entry; create the file with a `# Vesper History Archive — YYYY-MM` header if it doesn't exist).
69
+ 5. Rewrite `.vesper/history.md` to contain: the original header, the new digest line(s) referencing the archive file, then the last N entries verbatim (unchanged).
70
+
71
+ ### 2. Archive completed tracking stories
72
+
73
+ 1. List `.vesper/.tracking/stories/completed/`. For story files older than N days (default 30, or as specified), move them (via terminal `mv`, not delete) into `.vesper/.tracking/stories/completed/archive/YYYYMM/`, grouped by the month they were completed.
74
+ 2. Never touch `refining/`, `backlog/`, `inprogress/`, or `inreview/` — only `completed/`.
75
+ 3. Report the count moved and where.
76
+
77
+ ### Constraints (Compaction Mode only)
78
+
79
+ - **Never delete** — every rotation/archive is a move, not a removal.
80
+ - **Never touch active state** — anything in `.tracking/stories/` outside `completed/`, and the most recent N `history.md` entries, are off-limits.
81
+ - **Report what moved**: file counts and destination paths, so the user/orchestrator can verify nothing active was swept up.
82
+
57
83
  ## Terminal Discipline
58
84
 
59
85
  - **Timeout**: Every command gets one. Quick=15s, build=120s, test=300s. Default=30s.
@@ -200,6 +200,25 @@ When workspace is already set up:
200
200
  - Incomplete task (`[Started]` without `[Completed]`) → Resume by delegating to the appropriate agent
201
201
  - All complete → Proceed to Purpose Router
202
202
 
203
+ **Persisted-knowledge size check** (independent of the resumption logic above): if `.vesper/memory.jsonl` looks large (roughly >500 entities) or `.vesper/history.md` has grown long (roughly >150 entries), suggest the user run the `#compact-knowledge` prompt — a non-destructive workflow that rotates old history into an archive file and merges stale memory entities, so a *future* session doesn't have to ingest all of it. This is a suggestion, never a blocker — proceed with the user's actual request regardless.
204
+
205
+ ---
206
+
207
+ ## 🔌 MCP Readiness Preflight
208
+
209
+ Before the first delegation of a session (not on every turn — once state is confirmed, don't re-check), verify every MCP server this project declares is actually reachable, not just configured. This project's `.vscode/mcp.json` declares `vesper-indexing`, `sequential-thinking`, `memory`, plus any project-added servers (`vespercli mcp list`).
210
+
211
+ **Check**: run `vespercli mcp status` in terminal. This reuses the same status logic `vespercli mcp status` already uses for reporting — no new tool needed.
212
+
213
+ | Result | Action |
214
+ | :--- | :--- |
215
+ | All declared servers configured and the index/server artifacts exist | Proceed normally |
216
+ | A server is configured but its underlying process/tool isn't responding (e.g. a `vesper_search` call errors, memory tools are unavailable) | Tell the user which server is down and that a VS Code reload may be needed. Do NOT silently route around a missing required MCP tool. |
217
+ | `.vscode/mcp.json` itself looks stale/missing for this worktree (fresh worktree, never bootstrapped) | Run `vespercli worktree bootstrap --quiet` once, then re-check. This is the same idempotent step the folder-open task already runs — safe to re-run here if it somehow hasn't fired yet. |
218
+ | `vespercli mcp status` reports **MCP config drift** — a non-core server is live in `.vscode/mcp.json` but absent from `.vesperrc mcp.servers` | Non-blocking staleness signal: tracking and the generated docs are out of sync with the live config. Suggest the user run `/reinit` (or re-run `workspace-learner`) to resync `.vesperrc` and the generated docs. Do NOT auto-fix — it is a read-only diff. |
219
+
220
+ This is a readiness gate, not a blocker on every message — once confirmed for the session, don't re-run it before every delegation. The existing reactive rule ("if `vesper-indexing` is unavailable, STOP and ask") still applies mid-session if a server drops out later.
221
+
203
222
  ---
204
223
 
205
224
  ## 🎯 Purpose Router
@@ -636,6 +655,8 @@ For every multi-step purpose pipeline:
636
655
  - **Started log** must contain: Goal + Assigned Agent (enough to resume if interrupted)
637
656
  - When delegating to `@History Logger`, include your own model/session identity as the Author (e.g., `"Log that Phase 1 started. Author: GPT-5.5 (Copilot)."`) — useful given this workspace's tracking state may be shared with a Claude Code session (see cross-client note in Resumption below); `@History Logger` itself doesn't need to know why, it just places whatever value you give it
638
657
  - **Memory update**: After Implementation or Testing completes, `@Feature Wrap and Retrospective Agent` captures learnings via MCP Memory (`memory/*` tools) — see `#skill:mcp-memory`
658
+ - **Commit hygiene**: `vespercli init`/reinit installs a `pre-commit` git hook that auto-includes any dirty team-roster/context/history/`.tracking`/memory files into a commit that touches other work — this is what guarantees those files are never left out of a commit or PR, regardless of whether a human or an agent runs `git commit`. No pipeline step needs to commit these files itself; the hook covers it whenever a commit actually happens. Pushing remains a separate, always-confirmed action — the hook only affects what rides along inside a commit, never when/whether to push.
659
+ - **Cross-worktree merges**: `.vesper/history.md` and `.vesper/memory.jsonl` have git merge drivers configured (`.gitattributes`, set up by `vespercli init`) that resolve automatically — union for history, entity-aware merge for memory — so parallel worktrees converging on the base branch normally need no manual resolution for either file. `.github/copilot-instructions.md` and `.github/instructions/orchestration.instructions.md` are structured markdown with no automatic merge driver; if git reports a real conflict in either, do NOT hand-resolve the markdown diff yourself — delegate to `@Workspace Learner` with both conflicting versions and ask it to reconcile them, since it already owns regenerating these files.
639
660
 
640
661
  ### Resumption
641
662
 
@@ -195,6 +195,12 @@ The following sections are injected by VS Code into the system prompt. They are
195
195
 
196
196
  **Source of truth**: This file (`orchestration.instructions.md`) — specifically the **Team Roster** section — is the single authority for available agents, their roles, and their skill assignments.
197
197
 
198
+ ## Repository Policy
199
+
200
+ Base branch: [detect via `git symbolic-ref refs/remotes/origin/HEAD` or `git branch --show-current` if no remote yet, e.g. `main`/`master`/`develop`]
201
+
202
+ Every git worktree for this project is created from the base branch above — never from another worktree's branch. `.vesper/.tracking/`, `.vesper/history.md`, and `.vesper/memory.jsonl` are git-tracked and shared by every AI client working this workspace — never create a client-specific tracking folder. `.vesperrc`, `.vscode/mcp.json`, and `.vesper/index.db` are local/gitignored and regenerate automatically per worktree (`vespercli worktree bootstrap`, wired into the folder-open task and git hooks by `vespercli init`).
203
+
198
204
  ## Task Management
199
205
 
200
206
  [Task Management section from Phase 2 detection]
@@ -271,8 +277,9 @@ After Phase 3 is complete, install the Vesper team into the workspace using the
271
277
 
272
278
  Before any `vespercli add` or `vespercli catalog` call, check whether `.vesperrc` file exists in the workspace root.
273
279
 
274
- - **If `.vesperrc` exists**: Vesper is already initialized. Proceed to Step 1.
280
+ - **If `.vesperrc` exists AND this is NOT an explicit re-initialization request**: Vesper is already initialized. Proceed to Step 1.
275
281
  - **If `.vesperrc` does NOT exist**: Run `vespercli init --force-default` to initialize with all defaults (no user prompts). Then proceed to Step 1.
282
+ - **If this IS an explicit re-initialization request** (`.vesperrc` exists): still run `vespercli init --force-default` before proceeding. It's idempotent — this refreshes local-only config (`.mcp.json`, the `.gitignore` guard block, MCP tool approvals) to the current CLI version without touching anything you own (Team Roster, context, tracking). Then proceed to Step 1.
276
283
 
277
284
  #### Step 1 — Get Available Assets
278
285
 
@@ -0,0 +1,14 @@
1
+ ---
2
+ description: 'Compact persisted Vesper knowledge (history.md, memory graph, completed tracking stories) so a fresh session does not have to ingest all of it'
3
+ ---
4
+
5
+ # Compact Knowledge
6
+
7
+ Compact persisted Vesper knowledge — distinct from Claude Code's `/compact` or any context-window summarization; this compacts what's **on disk / in the memory graph**, not the current conversation.
8
+
9
+ Delegate:
10
+
11
+ 1. `@History Logger` in Compaction Mode: rotate `.vesper/history.md` (archive entries older than the last 30 into `.vesper/history-archive/YYYYMM.md`) and archive `.vesper/.tracking/stories/completed/` entries older than 30 days.
12
+ 2. `@Feature Wrap and Retrospective Agent` in Memory Compaction Mode: merge/dedupe stale entities in the MCP memory graph, never touching `current_task` or active entities.
13
+
14
+ Report what was archived/merged from both. Nothing is deleted — only moved to archive files or consolidated within the memory graph.
@@ -0,0 +1,136 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Git custom merge driver for .vesper/memory.jsonl (the MCP memory server's
4
+ * knowledge-graph store — one JSON object per line, either
5
+ * {type:"entity", name, entityType, observations:[...]} or
6
+ * {type:"relation", from, to, relationType}).
7
+ *
8
+ * A naive line-based/union merge is unsafe here: two worktrees editing the
9
+ * graph concurrently would just concatenate lines, duplicating entities and
10
+ * resurrecting anything the compaction workflow (/compact-knowledge)
11
+ * deliberately deleted. This driver does a real 3-way merge keyed by entity
12
+ * name / relation identity instead:
13
+ *
14
+ * - Present on both sides (possibly with different observations) -> keep,
15
+ * union of observations (deduped).
16
+ * - Present on one side only, and NOT in the ancestor -> a genuinely new
17
+ * addition from that side -> keep.
18
+ * - Present on one side only, and WAS in the ancestor -> the other side
19
+ * deleted it on purpose (e.g. compaction) -> respect the deletion, drop it.
20
+ *
21
+ * Registered via `git config merge.vesper-memory.driver` (see
22
+ * configureVesperMergeDriver in src/cli/utils/settings.js) and invoked by git
23
+ * as: merge-memory-jsonl.js %O %A %B
24
+ * %O = ancestor (common base) temp file
25
+ * %A = current branch's version — ALSO where the merged result must be written
26
+ * %B = other branch's version temp file
27
+ * Exit 0 always: this driver's whole point is to resolve deterministically
28
+ * without ever falling back to conflict markers.
29
+ */
30
+
31
+ import { readFileSync, writeFileSync } from 'node:fs';
32
+
33
+ function parseJsonl(path) {
34
+ let content;
35
+ try {
36
+ content = readFileSync(path, 'utf-8');
37
+ } catch {
38
+ return [];
39
+ }
40
+ return content
41
+ .split('\n')
42
+ .map((line) => line.trim())
43
+ .filter(Boolean)
44
+ .map((line) => {
45
+ try {
46
+ return JSON.parse(line);
47
+ } catch {
48
+ return null;
49
+ }
50
+ })
51
+ .filter(Boolean);
52
+ }
53
+
54
+ function entityKey(record) {
55
+ return `entity:${record.name}`;
56
+ }
57
+
58
+ function relationKey(record) {
59
+ return `relation:${record.from}|${record.to}|${record.relationType}`;
60
+ }
61
+
62
+ function keyOf(record) {
63
+ return record.type === 'relation' ? relationKey(record) : entityKey(record);
64
+ }
65
+
66
+ function toMap(records) {
67
+ const map = new Map();
68
+ for (const record of records) {
69
+ map.set(keyOf(record), record);
70
+ }
71
+ return map;
72
+ }
73
+
74
+ function mergeEntity(a, b) {
75
+ const observations = Array.from(new Set([...(a.observations || []), ...(b.observations || [])]));
76
+ return {
77
+ type: 'entity',
78
+ name: a.name,
79
+ entityType: a.entityType || b.entityType,
80
+ observations,
81
+ };
82
+ }
83
+
84
+ function threeWayMerge(oMap, aMap, bMap) {
85
+ const allKeys = new Set([...aMap.keys(), ...bMap.keys()]);
86
+ const merged = [];
87
+
88
+ for (const key of allKeys) {
89
+ const inO = oMap.has(key);
90
+ const inA = aMap.has(key);
91
+ const inB = bMap.has(key);
92
+
93
+ if (inA && inB) {
94
+ const a = aMap.get(key);
95
+ const b = bMap.get(key);
96
+ merged.push(a.type === 'entity' ? mergeEntity(a, b) : a);
97
+ continue;
98
+ }
99
+
100
+ // Present on exactly one side.
101
+ const onlySide = inA ? aMap.get(key) : bMap.get(key);
102
+ if (inO) {
103
+ // The other side deleted it on purpose (e.g. /compact-knowledge). Respect it.
104
+ continue;
105
+ }
106
+ // Genuinely new on the side that has it.
107
+ merged.push(onlySide);
108
+ }
109
+
110
+ return merged;
111
+ }
112
+
113
+ function main() {
114
+ const [, , ancestorPath, currentPath, otherPath] = process.argv;
115
+
116
+ const oRecords = parseJsonl(ancestorPath);
117
+ const aRecords = parseJsonl(currentPath);
118
+ const bRecords = parseJsonl(otherPath);
119
+
120
+ const oMap = toMap(oRecords);
121
+ const aMap = toMap(aRecords);
122
+ const bMap = toMap(bRecords);
123
+
124
+ const merged = threeWayMerge(oMap, aMap, bMap);
125
+
126
+ // Entities first, then relations, each sorted by key for stable diffs.
127
+ const entities = merged.filter((r) => r.type === 'entity').sort((x, y) => x.name.localeCompare(y.name));
128
+ const relations = merged
129
+ .filter((r) => r.type === 'relation')
130
+ .sort((x, y) => relationKey(x).localeCompare(relationKey(y)));
131
+
132
+ const lines = [...entities, ...relations].map((r) => JSON.stringify(r));
133
+ writeFileSync(currentPath, lines.length ? `${lines.join('\n')}\n` : '', 'utf-8');
134
+ }
135
+
136
+ main();
@@ -0,0 +1,23 @@
1
+ #!/bin/sh
2
+ # Vesper: bootstrap this worktree's local-only artifacts (.mcp.json, code
3
+ # index, gitignore, git hooks) whenever a checkout happens — including
4
+ # `git worktree add`, which runs a checkout in the new worktree. This is the
5
+ # cross-client safety net: it fires regardless of which editor/agent opens
6
+ # the worktree, catching the case where neither the Claude SessionStart hook
7
+ # nor the Copilot folderOpen task ran first.
8
+ #
9
+ # `vespercli worktree bootstrap` itself no-ops on a workspace that was never
10
+ # vesperized (detected via git-tracked markers, not the gitignored
11
+ # .vesperrc), so this hook is safe to fire on every plain checkout too.
12
+ # Best-effort and non-blocking: never fails the checkout.
13
+ #
14
+ # Installed idempotently by `vespercli init` / re-init. Safe to remove:
15
+ # Vesper re-adds this block on the next init/reinit.
16
+
17
+ # <!-- vesper:hook:start -->
18
+ if command -v vespercli >/dev/null 2>&1; then
19
+ vespercli worktree bootstrap --quiet >/dev/null 2>&1 || true
20
+ fi
21
+ # <!-- vesper:hook:end -->
22
+
23
+ exit 0
@@ -0,0 +1,61 @@
1
+ #!/bin/sh
2
+ # Vesper: ensure project-knowledge files ride along with any commit that
3
+ # touches other work — regardless of whether a human or an agent triggered
4
+ # the commit. Fixes the failure mode where code/docs get committed (and a PR
5
+ # opened) while the accompanying team roster, context, history, or memory
6
+ # updates are left uncommitted.
7
+ #
8
+ # Installed idempotently by `vespercli init` / re-init. Mirrors
9
+ # VESPER_GIT_PATHS in src/cli/utils/settings.js — keep the list in sync if
10
+ # you edit one side.
11
+ #
12
+ # Safe to remove: Vesper re-adds this block on the next init/reinit, it
13
+ # never touches hook content outside its own marked section.
14
+
15
+ # <!-- vesper:hook:start -->
16
+ vesper_git_paths=".claude/vesper/orchestration.md .claude/vesper/context.md .vesper/history.md .vesper/.tracking .vesper/memory.jsonl CLAUDE.md .github/copilot-instructions.md"
17
+
18
+ staged=$(git diff --cached --name-only)
19
+ if [ -z "$staged" ]; then
20
+ exit 0
21
+ fi
22
+
23
+ is_vesper_path() {
24
+ candidate="$1"
25
+ for p in $vesper_git_paths; do
26
+ case "$candidate" in
27
+ "$p"|"$p"/*) return 0 ;;
28
+ esac
29
+ done
30
+ return 1
31
+ }
32
+
33
+ # Only act when this commit touches something *outside* Vesper's own paths
34
+ # — i.e. this looks like real work, not a Vesper-only commit.
35
+ has_other_work=0
36
+ for f in $staged; do
37
+ if ! is_vesper_path "$f"; then
38
+ has_other_work=1
39
+ break
40
+ fi
41
+ done
42
+ if [ "$has_other_work" -eq 0 ]; then
43
+ exit 0
44
+ fi
45
+
46
+ included=""
47
+ for p in $vesper_git_paths; do
48
+ [ -e "$p" ] || continue
49
+ dirty=$(git status --porcelain -- "$p" | awk 'substr($0,2,1) != " " { print; exit }')
50
+ if [ -n "$dirty" ]; then
51
+ git add -- "$p"
52
+ included="$included $p"
53
+ fi
54
+ done
55
+
56
+ if [ -n "$included" ]; then
57
+ echo "vesper: included updated$included in this commit"
58
+ fi
59
+ # <!-- vesper:hook:end -->
60
+
61
+ exit 0
package/dist/cli.min.js CHANGED
@@ -1,17 +1,38 @@
1
- var Yt=(e,t)=>()=>(e&&(t=e(e=0)),t);import{access as Ht,constants as zt,stat as tr}from"node:fs/promises";async function h(e){try{return await Ht(e,zt.F_OK),!0}catch{return!1}}var N=Yt(()=>{});import{Command as Bn}from"commander";import{readFileSync as Kn,existsSync as Jn}from"node:fs";import{fileURLToPath as Yn}from"node:url";import{dirname as De,join as Jt}from"node:path";N();import{resolve as Gs,basename as qs}from"node:path";import{spawn as Bs}from"node:child_process";import{confirm as ee,input as Ks,number as Js,select as Ys,checkbox as Hs}from"@inquirer/prompts";import{readFile as R,writeFile as H,mkdir as xe,readdir as rs}from"node:fs/promises";import{join as A,dirname as X}from"node:path";import{homedir as je}from"node:os";import os from"strip-json-comments";import{fileURLToPath as Xt}from"node:url";import{dirname as _e,join as ne,resolve as Qt}from"node:path";import{readdir as Zt}from"node:fs/promises";import{existsSync as es}from"node:fs";var ts=Xt(import.meta.url),ss=_e(ts);function ns(e){let t=e;for(;t!==_e(t);){if(es(ne(t,"package.json")))return t;t=_e(t)}return Qt(e,"..","..","..")}var J=ns(ss),O=ne(J,"assets"),Le=ne(O,"core");function Se(e){if(!e||typeof e!="string")throw new Error("Asset name is required");if(e.includes("..")||e.includes("/")||e.includes("\\"))throw new Error(`Invalid asset name: ${e}`)}var b={agents:{dir:"agents",destDir:"agents",extension:".agent.md",isFolder:!0},prompts:{dir:"prompts",destDir:"prompts",extension:".prompt.md",isFolder:!0},instructions:{dir:"instructions",destDir:"instructions",extension:".instructions.md",isFolder:!0},skills:{dir:"skills",destDir:"skills",extension:"",isFolder:!0}};async function Y(e){let t=b[e];if(!t)throw new Error(`Unknown asset type: ${e}`);let s=ne(O,t.dir);try{return(await Zt(s,{withFileTypes:!0})).filter(o=>o.isDirectory()&&!o.name.startsWith(".")).map(o=>o.name)}catch{return[]}}function Ne(e,t){Se(t);let s=b[e];if(!s)throw new Error(`Unknown asset type: ${e}`);return ne(O,s.dir,t)}function j(e){let t=je();return e.startsWith(t)?"~"+e.slice(t.length).replace(/\\/g,"/"):e.replace(/\\/g,"/")}var as=/node_modules\/(?:vesper-cli|vespercli)\/(.+)$/;function le(e){if(typeof e!="string")return e;let t=e.match(as);return t?j(A(J,t[1])):e}function is(e){return e==="vesper-cli"||e.startsWith("vesper-cli ")||e.endsWith("/vesper-cli")}var z={agents:"chat.agentFilesLocations",instructions:"chat.instructionsFilesLocations",prompts:"chat.promptFilesLocations",skills:"chat.agentSkillsLocations"},re="chat.tools.terminal.autoApprove",Ve="chat.tools.terminal.enableAutoApprove",Ae="chat.tools.autoApprove",v="chat.tools.eligibleForAutoApproval",Ue="chat.agent.maxRequests",We="chat.includeReferencedInstructions",Ge="chat.customAgentInSubagent.enabled",qe="chat.agent.enabled",Be="github.copilot.chat.omitBaseAgentInstructions",Ke="chat.mcp.discovery.enabled",Je="chat.mcp.autoStart",_="github.copilot.chat.additionalReadAccessPaths",$={maxRequests:300,terminalEnableAutoApprove:!0,omitBaseAgentInstructions:!0,enableMcpServer:!0},cs=[Ue,We,Ge,qe,Be,Ke,Je,Ve,re,Ae,v],ls=["vesper-indexing","sequential-thinking","memory"],Re=["react-scripts","**/node_modules/.bin/react-scripts","next","**/node_modules/.bin/next","vite","**/node_modules/.bin/vite","webpack","**/node_modules/.bin/webpack","turbo","**/node_modules/.bin/turbo","tsc","**/node_modules/.bin/tsc","tsup","**/node_modules/.bin/tsup","esbuild","**/node_modules/.bin/esbuild","rollup","**/node_modules/.bin/rollup","parcel","**/node_modules/.bin/parcel","jest","**/node_modules/.bin/jest","vitest","**/node_modules/.bin/vitest","npx vitest","pnpm vitest","pnpm vitest run","pnpm exec vitest","pnpm dlx vitest","mocha","**/node_modules/.bin/mocha","playwright","**/node_modules/.bin/playwright","npx playwright open","npx playwright test","npx playwright show-report","npx playwright codegen","open playwright","open playwright-report/index.html",'ps aux | grep "playwright test" | grep -v grep | wc -l',"cypress","**/node_modules/.bin/cypress","pytest","npx","pnpm dlx","pnpm exec","yarn dlx","npm test","npm run","npm start","npm run test","npm run build","npm run dev","npm run lint","pnpm test","pnpm run","pnpm start","pnpm tsc","yarn test","yarn run","yarn start","eslint","**/node_modules/.bin/eslint","pnpm eslint","prettier","**/node_modules/.bin/prettier","biome","**/node_modules/.bin/biome","stylelint","**/node_modules/.bin/stylelint","mkdir","touch","cat","ls","head","tail","wc","grep","find","tree","file","stat","realpath","basename","dirname","awk","sed","cut","sort","uniq","tr","xargs","column","paste","join","comm","diff","cmp","git status","git log","git diff","git branch","git show","git remote","git tag","git rev-parse","git describe","git ls-files","git ls-tree","git blame","git shortlog","pushd","popd","dirs","echo","pwd","which","type","env","printenv","date","hostname","whoami","uname","lsof","pkill","node --version","npm --version","pnpm --version","yarn --version","python --version","python3 --version","curl -I *","curl --head *","curl -sI *","curl -s http://localhost:*","curl -s http://127.0.0.1:*","curl -sf http://localhost:*","curl -sf http://127.0.0.1:*","curl --fail http://localhost:*","curl --fail http://127.0.0.1:*","tsx","**/node_modules/.bin/tsx","npx tsx","/^(\\w+=\\S+\\s+)+(npx|node|tsx|npm|pnpm|yarn)\\b/","vespercli","vespercli init","vespercli add","vespercli list","vespercli ls","vespercli reset","vespercli catalog","**/node_modules/.bin/vespercli","mcp: vesper-indexing: vesper_search","mcp: vesper-indexing: vesper_symbols","mcp: vesper-indexing: vesper_status","mcp: vesper-indexing: vesper_reindex","python3 << 'PYEOF'",'python3 << "PYEOF"',"python3 << 'EOF'",'python3 << "EOF"',"python3 << 'END'","python << 'PYEOF'",'python << "PYEOF"',"python << 'EOF'","cat << 'EOF'",'cat << "EOF"',"cat << 'END'","bash << 'EOF'","sh << 'EOF'","cat << 'RESEARCH_EOF'",'cat << "RESEARCH_EOF"',"RESEARCH_EOF","tee","node -e","python3 -c","python -c"],M=["vesper_search","vesper_symbols","vesper_status","vesper_reindex","resolve-library-id","get-library-docs","query-docs","sequentialthinking","create_entities","create_relations","add_observations","delete_entities","delete_observations","delete_relations","read_graph","search_nodes","open_nodes"],Ce={"clickup-agent":["clickup_add_tag_to_task","clickup_add_time_entry","clickup_attach_task_file","clickup_create_document","clickup_create_document_page","clickup_create_folder","clickup_create_list","clickup_create_list_in_folder","clickup_create_task","clickup_create_task_comment","clickup_find_member_by_name","clickup_get_chat_channels","clickup_get_current_time_entry","clickup_get_document_pages","clickup_get_folder","clickup_get_list","clickup_get_task","clickup_get_task_comments","clickup_get_task_time_entries","clickup_get_workspace_hierarchy","clickup_get_workspace_members","clickup_list_document_pages","clickup_remove_tag_from_task","clickup_resolve_assignees","clickup_search","clickup_send_chat_message","clickup_start_time_tracking","clickup_stop_time_tracking","clickup_update_document_page","clickup_update_folder","clickup_update_list","clickup_update_task"]},oe={"vesper-indexing":{description:"Fast code search with semantic indexing",config:{type:"stdio",command:"node",args:["${VESPER_INDEXING_PATH}"],env:{VESPER_INDEX_ROOT:"${workspaceFolder}"}},tools:["vesper_search","vesper_symbols","vesper_status","vesper_reindex"]},context7:{description:"Documentation lookup for libraries",config:{type:"stdio",command:"npx",args:["-y","@upstash/context7-mcp"]},tools:["resolve-library-id","get-library-docs","query-docs"]},"sequential-thinking":{description:"Step-by-step reasoning for complex problems",config:{type:"stdio",command:"npx",args:["-y","@modelcontextprotocol/server-sequential-thinking"]},tools:["sequentialthinking"]},clickup:{description:"ClickUp project management integration",config:{type:"stdio",command:"npx",args:["-y","@anthropics/mcp-clickup"],env:{CLICKUP_API_KEY:"${env:CLICKUP_API_KEY}",CLICKUP_TEAM_ID:"${env:CLICKUP_TEAM_ID}"}},tools:["clickup_add_tag_to_task","clickup_add_time_entry","clickup_attach_task_file","clickup_create_document","clickup_create_document_page","clickup_create_folder","clickup_create_list","clickup_create_list_in_folder","clickup_create_task","clickup_create_task_comment","clickup_find_member_by_name","clickup_get_chat_channels","clickup_get_current_time_entry","clickup_get_document_pages","clickup_get_folder","clickup_get_list","clickup_get_task","clickup_get_task_comments","clickup_get_task_time_entries","clickup_get_workspace_hierarchy","clickup_get_workspace_members","clickup_list_document_pages","clickup_remove_tag_from_task","clickup_resolve_assignees","clickup_search","clickup_send_chat_message","clickup_start_time_tracking","clickup_stop_time_tracking","clickup_update_document_page","clickup_update_folder","clickup_update_list","clickup_update_task"]},memory:{description:"Persistent knowledge graph memory for AI agents",config:{type:"stdio",command:"npx",args:["-y","@modelcontextprotocol/server-memory"],env:{MEMORY_FILE_PATH:"${workspaceFolder}/.vesper/memory.jsonl"}},tools:["create_entities","create_relations","add_observations","delete_entities","delete_observations","delete_relations","read_graph","search_nodes","open_nodes"]}};var k={FOLDER:"folder",WORKSPACE_FILE:"workspace"};async function ds(e){try{let s=(await rs(e,{withFileTypes:!0})).find(n=>n.isFile()&&n.name.endsWith(".code-workspace"));return s?A(e,s.name):null}catch{return null}}async function y(e){let t=await ds(e);return t?{type:k.WORKSPACE_FILE,settingsPath:t,workspaceFile:t}:{type:k.FOLDER,settingsPath:A(e,".vscode","settings.json"),workspaceFile:null}}function ke(e,t=null){return t?.workspaceFile?A(X(t.workspaceFile),".vesperrc"):A(e,".vesperrc")}function de(e){let t=os(e,{trailingCommas:!0});return JSON.parse(t)}async function S(e){let t=await y(e);try{let s=await R(t.settingsPath,"utf-8"),n=de(s);return t.type===k.WORKSPACE_FILE?n.settings||{}:n}catch(s){if(s.code==="ENOENT")return{};if(s instanceof SyntaxError){if(t.type===k.WORKSPACE_FILE)throw new Error(`Failed to parse workspace file: ${t.settingsPath}. ${s.message}`);return{}}throw s}}async function C(e,t){let s=await y(e);if(s.type===k.WORKSPACE_FILE){let n;try{let o=await R(s.settingsPath,"utf-8");n=de(o)}catch(o){if(o.code==="ENOENT")n={folders:[],settings:{}};else throw new Error(`Failed to read workspace file: ${s.settingsPath}. ${o.message}`)}n.settings=t,await H(s.settingsPath,JSON.stringify(n,null," "),"utf-8")}else{let n=X(s.settingsPath);await xe(n,{recursive:!0}),await H(s.settingsPath,JSON.stringify(t,null," "),"utf-8")}}function ps(e){return A(e,".vesper","tracking.json")}async function g(e){let t=await y(e),s=ke(e,t),n=ps(e),o=A(e,".vesperrc");try{let a=await R(s,"utf-8");return JSON.parse(a)}catch{if(s!==o)try{let a=await R(o,"utf-8");return JSON.parse(a)}catch{}try{let a=await R(n,"utf-8");return JSON.parse(a)}catch{return{paths:[],addedAt:null,workspaceType:null,settingsPath:null}}}}async function us(e){try{let t=await R(e,"utf-8"),n=de(t).folders||[],o=X(e);return n.map(a=>{let i=a.path||a;return i.startsWith("/")||i.startsWith("~")?i.replace(/^~/,je()):A(o,i)})}catch{return[]}}async function Ye(e){let t=await y(e);if(t.type!==k.WORKSPACE_FILE)return{found:!1,paths:[]};let s=X(t.workspaceFile),n=A(s,".vesperrc"),o=await us(t.workspaceFile),a=[];for(let i of o){let c=A(i,".vesperrc");if(c!==n)try{let d=await R(c,"utf-8"),l=JSON.parse(d);a.push({folderPath:i,vesperrcPath:c,tracking:l})}catch{}}return{found:a.length>0,paths:a}}async function He(e,t,s){let n=await y(e),o=ke(e,n),a={...s,workspaceType:k.WORKSPACE_FILE,settingsPath:n.settingsPath,migratedFrom:t,migratedAt:new Date().toISOString()};await H(o,JSON.stringify(a,null,2),"utf-8");try{let{unlink:i}=await import("node:fs/promises");await i(t)}catch{}return{success:!0,newPath:o}}async function P(e,t){let s=await y(e),n=ke(e,s);await H(n,JSON.stringify(t,null,2),"utf-8")}async function ze(e,t){let s=await y(e),n=await S(e),o=await g(e),a=[],i=[];for(let{path:c,settingKey:d}of t){if(n[d]||(n[d]={}),n[d][c]){i.push(c),o.paths.includes(c)||o.paths.push(c);continue}n[d][c]=!0,a.push(c),o.paths.includes(c)||o.paths.push(c)}return a.length>0&&await C(e,n),o.paths.length>0&&(o.addedAt=o.addedAt||new Date().toISOString(),o.updatedAt=new Date().toISOString(),o.workspaceType=s.type,o.settingsPath=s.settingsPath,await P(e,o)),{added:a,skipped:i,workspaceType:s.type}}async function Xe(e){let t=await S(e),s=await g(e),n={paths:[],settings:[],mcpServers:[],agentTools:[]},o=/vespercli|vesper-cli/;for(let u of Object.values(z))if(t[u]){for(let p of Object.keys(t[u])){let f=s.paths?.includes(p),m=o.test(p);(f||m)&&(delete t[u][p],n.paths.includes(p)||n.paths.push(p))}Object.keys(t[u]).length===0&&delete t[u]}let a=s.readAccessPaths||[];if(a.length>0){let u=t[_]||[],p=u.filter(f=>!a.includes(f));p.length!==u.length&&(p.length>0?t[_]=p:delete t[_],n.settings.push(_))}for(let u of cs)t[u]!==void 0&&(delete t[u],n.settings.push(u));let i=s.mcp?.agentTools||{};for(let[u,p]of Object.entries(i))n.agentTools.push({agent:u,tools:p});(n.paths.length>0||n.settings.length>0)&&await C(e,t);let c=await U(e),d=s.mcp?.servers||[],l=[...new Set([...ls,...d])];if(c.servers){for(let u of l)c.servers[u]&&(delete c.servers[u],n.mcpServers.push(u));if(n.mcpServers.length>0){let u=ue(e),p=X(u);await xe(p,{recursive:!0}),await H(u,JSON.stringify(c,null," "),"utf-8")}}return await P(e,{paths:[],readAccessPaths:[],addedAt:null,workspaceType:null,settingsPath:null,mcp:null}),{removed:n}}async function pe(e){return(await g(e)).paths.length>0}async function D(e){let t=await g(e),s=[];return Array.isArray(t.paths)&&t.paths.length>0&&s.push("copilot"),t.claude&&s.push("claude"),s}var fs=["agents","prompts","instructions"];function gs(){let e=[];for(let n of fs){let o=b[n],a=z[n];if(a&&o){let i=j(A(O,"core",o.dir));e.push({path:i,settingKey:a,type:n})}}let t=z.skills;if(t){let n=j(A(O,"core","skills"));e.push({path:n,settingKey:t,type:"skills"})}let s=b.skills;if(t&&s){let n=j(A(O,s.dir));e.push({path:n,settingKey:t,type:"skills"})}return e}async function Qe(e,t=!0){let s=await y(e),n=await S(e);if(n[Ve]=t,t){n[re]||(n[re]={});for(let o of Re)n[re][o]=!0}return await C(e,n),{configured:t?Re.length:0,workspaceType:s.type}}async function Ze(e,t={}){let{maxRequests:s=$.maxRequests,omitBaseAgentInstructions:n=$.omitBaseAgentInstructions}=t,o=await S(e);o[Ue]=s,o[We]=!0,o[Ge]=!0,o[qe]=!0,o[Be]=n,o[Ke]=!0,o[Je]="newAndOutdated",o[_]||(o[_]=[]),await C(e,o)}async function et(e,t){let s=await S(e),n=s[_]||[];n.includes(t)||(n.push(t),s[_]=n,await C(e,s));let o=await g(e);return o.readAccessPaths||(o.readAccessPaths=[]),o.readAccessPaths.includes(t)||(o.readAccessPaths.push(t),o.updatedAt=new Date().toISOString(),await P(e,o)),n}async function tt(e,t){let s=await S(e),n=s[_]||[],o=n.indexOf(t);o!==-1&&(n.splice(o,1),s[_]=n,await C(e,s));let a=await g(e);if(a.readAccessPaths){let i=a.readAccessPaths.indexOf(t);i!==-1&&(a.readAccessPaths.splice(i,1),a.updatedAt=new Date().toISOString(),await P(e,a))}return n}async function st(e){return(await S(e))[_]||[]}function nt(e){let t=b[e];if(!t)throw new Error(`Unknown asset type: ${e}`);let s=z[e];return{path:j(A(O,t.dir)),settingKey:s,type:e}}function G(e,t){if(Se(t),!b[e])throw new Error(`Unknown asset type: ${e}`);let n=z[e];return{path:j(Ne(e,t)),settingKey:n,type:e,name:t}}async function Q(e){return(await g(e)).paths}async function rt(e){let t={assetPaths:0,readAccess:0,commandKeys:0,trackingPaths:0,mcpArgs:0},s=(p,f)=>{let m=[];for(let T of p){let se=le(T);se!==T&&t[f]++,m.includes(se)||m.push(se)}return m},n=await S(e),o=!1;for(let p of Object.values(z)){let f=n[p];if(!(!f||typeof f!="object"))for(let m of Object.keys(f)){let T=le(m);if(T===m)continue;let se=f[m];delete f[m],f[T]=f[T]===!0?!0:se,t.assetPaths++,o=!0}}if(Array.isArray(n[_])){let p=t.readAccess;n[_]=s(n[_],"readAccess"),t.readAccess!==p&&(o=!0)}let a=n[re];if(a&&typeof a=="object")for(let p of Object.keys(a))is(p)&&(delete a[p],t.commandKeys++,o=!0);o&&await C(e,n);let i=await g(e),c=!1;if(Array.isArray(i.paths)){let p=t.trackingPaths;i.paths=s(i.paths,"trackingPaths"),t.trackingPaths!==p&&(c=!0)}if(Array.isArray(i.readAccessPaths)){let p=[];for(let f of i.readAccessPaths){let m=le(f);m!==f&&(c=!0),p.includes(m)||p.push(m)}i.readAccessPaths=p}c&&(i.updatedAt=new Date().toISOString(),await P(e,i));let d=await U(e),l=d.servers?.["vesper-indexing"];if(l&&Array.isArray(l.args)){let p=!1;l.args=l.args.map(f=>{let m=le(f);return m!==f&&(t.mcpArgs++,p=!0),m}),p&&await fe(e,d)}return{migrated:t.assetPaths+t.readAccess+t.commandKeys+t.trackingPaths+t.mcpArgs>0,changed:t}}async function ot(e){let t=await y(e),s=await S(e),n=await g(e),o=gs(),a=[],i=[];for(let{path:l,settingKey:u}of o)s[u]||(s[u]={}),s[u][l]===!0?i.push(l):(s[u][l]=!0,a.push(l)),n.paths.includes(l)||n.paths.push(l);let c=O,d=s[_]||[];return d.includes(c)||(d.push(c),s[_]=d,a.push(c)),n.readAccessPaths||(n.readAccessPaths=[]),n.readAccessPaths.includes(c)||n.readAccessPaths.push(c),a.length>0&&await C(e,s),n.addedAt=n.addedAt||new Date().toISOString(),n.updatedAt=new Date().toISOString(),n.workspaceType=t.type,n.settingsPath=t.settingsPath,await P(e,n),{added:a,existed:i,workspaceType:t.type}}function ue(e){return A(e,".vscode","mcp.json")}function V(){return A(J,"src","mcp","vesper-indexing","dist","index.js")}async function U(e){let t=ue(e);try{let s=await R(t,"utf-8");return de(s)}catch(s){if(s.code==="ENOENT")return{servers:{}};if(s instanceof SyntaxError)return{servers:{}};throw s}}async function fe(e,t){let s=ue(e),n=X(s);await xe(n,{recursive:!0}),await H(s,JSON.stringify(t,null," "),"utf-8")}async function ae(e,t=!0){let s=await U(e),n=j(V()),o=[];if(s.servers||(s.servers={}),t?(s.servers["vesper-indexing"]={type:"stdio",command:"node",args:[n],env:{VESPER_INDEX_ROOT:"${workspaceFolder}"}},o.push("vesper-indexing"),s.servers["sequential-thinking"]={type:"stdio",command:"npx",args:["-y","@modelcontextprotocol/server-sequential-thinking"]},o.push("sequential-thinking"),s.servers.memory={type:"stdio",command:"npx",args:["-y","@modelcontextprotocol/server-memory"],env:{MEMORY_FILE_PATH:"${workspaceFolder}/.vesper/memory.jsonl"}},o.push("memory")):(delete s.servers["vesper-indexing"],delete s.servers["sequential-thinking"],delete s.servers.memory),await fe(e,s),t&&o.length>0){let a=await g(e);a.mcp=a.mcp||{},a.mcp.servers=o,a.mcp.updatedAt=new Date().toISOString(),await P(e,a)}return{configured:t,mcpPath:ue(e),servers:o}}async function at(e){return!!(await U(e)).servers?.["vesper-indexing"]}async function it(e){let t=await y(e),s=await S(e);s[Ae]=!1,s[v]||(s[v]={});for(let n of M)s[v][n]=!0;return await C(e,s),{configured:M.length,workspaceType:t.type}}async function ct(e,t){let s=Ce[t];if(!s||s.length===0)return{added:[],agentName:t};let n=await S(e),o=await y(e),a=await g(e,o);n[v]||(n[v]={});let i=[];for(let c of s)n[v][c]||(n[v][c]=!0,i.push(c));return i.length>0&&(await C(e,n),a.mcp=a.mcp||{},a.mcp.agentTools=a.mcp.agentTools||{},a.mcp.agentTools[t]=s,a.mcp.updatedAt=new Date().toISOString(),await P(e,a)),{added:i,agentName:t}}async function lt(e,t){let s=oe[t];if(!s)return{added:!1,serverName:t,tools:[],error:`Unknown MCP server: ${t}`};let n=await U(e),o=await S(e),a=await y(e),i=await g(e,a);if(n.servers||(n.servers={}),n.servers[t])return{added:!1,serverName:t,tools:[],error:"Already configured"};let c=JSON.parse(JSON.stringify(s.config));if(t==="vesper-indexing"){let l=j(V());c.args&&(c.args=c.args.map(u=>u==="${VESPER_INDEXING_PATH}"?l:u))}n.servers[t]=c,await fe(e,n),o[v]||(o[v]={});let d=[];for(let l of s.tools||[])o[v][l]||(o[v][l]=!0,d.push(l));return o[Ae]=!1,await C(e,o),i.mcp=i.mcp||{},i.mcp.servers=i.mcp.servers||[],i.mcp.servers.includes(t)||i.mcp.servers.push(t),i.mcp.updatedAt=new Date().toISOString(),await P(e,i),{added:!0,serverName:t,tools:d}}async function dt(e,t){let s=oe[t],n=await U(e),o=await S(e),a=await y(e),i=await g(e,a),c=!1;n.servers&&n.servers[t]&&(delete n.servers[t],await fe(e,n),c=!0);let d=[];if(s&&o[v]){for(let l of s.tools||[])o[v][l]&&(delete o[v][l],d.push(l));d.length>0&&await C(e,o)}return i.mcp?.servers&&(i.mcp.servers=i.mcp.servers.filter(l=>l!==t),i.mcp.updatedAt=new Date().toISOString(),await P(e,i)),{removed:c,serverName:t,tools:d}}import{readFile as F,writeFile as E,mkdir as q,readdir as ut,rm as pt,cp as ft}from"node:fs/promises";import{join as w,dirname as Pe,basename as ms}from"node:path";import{homedir as hs}from"node:os";N();var Z=w(O,"claude"),gt=["agents","commands","skills"],ge="vesper";function B(e=ge){return w(hs(),".claude","skills",e)}function mt(e){return w(e,".claude","vesper")}function ht(e){return w(e,"CLAUDE.md")}function K(e){return w(e,".mcp.json")}function me(e){return w(e,".claude","settings.json")}function vt(e,t){return t?e.replace(/^(name:\s*)([a-z0-9-]+)/m,(s,n,o)=>o.startsWith(t)?s:`${n}${t}${o}`):e}async function vs(e,t,s,n){if(!await h(e))return{copied:0};await q(t,{recursive:!0});let o=await ut(e,{withFileTypes:!0}),a=0;for(let i of o){let c=w(e,i.name);if(i.isDirectory()){await ft(c,w(t,i.name),{recursive:!0}),a+=1;continue}if(!i.name.endsWith(".md"))continue;let d=await F(c,"utf-8"),l=vt(d,s),u=n&&s&&!i.name.startsWith(s)?`${s}${i.name}`:i.name;await E(w(t,u),l,"utf-8"),a+=1}return{copied:a}}async function ws(e,t,s){let n=w(e,".claude-plugin");await q(n,{recursive:!0});let o={name:t,description:"Vesper specialist catalog \u2014 subagents, slash commands, and skills for AI-orchestrated development.",version:s};await E(w(n,"plugin.json"),JSON.stringify(o,null,2),"utf-8")}async function he({pluginName:e=ge,namePrefix:t="",version:s="0.0.0"}={}){let n=B(e),o={};for(let a of gt){let i=w(Z,a),c=w(n,a),l=await vs(i,c,a==="skills"?"":t,a!=="skills");o[a]=l.copied}return await ws(n,e,s),{pluginDir:n,counts:o}}async function wt(e,t,{pluginName:s=ge,namePrefix:n=""}={}){let o=B(s),a=w(o,e);if(await q(a,{recursive:!0}),e==="skills"){let p=w(Z,"skills",t);if(!await h(p))throw new Error(`Skill "${t}" not found in assets/claude/skills/`);return await ft(p,w(a,t),{recursive:!0}),{installedAs:t}}let i=".md",c=w(Z,e,`${t}${i}`);if(!await h(c))throw new Error(`${e.slice(0,-1)} "${t}" not found in assets/claude/${e}/`);let d=await F(c,"utf-8"),l=vt(d,n),u=n&&!t.startsWith(n)?`${n}${t}${i}`:`${t}${i}`;return await E(w(a,u),l,"utf-8"),{installedAs:ms(u,i)}}async function yt(e=ge){let t=B(e),s={};for(let n of gt){let o=w(t,n);if(!await h(o)){s[n]=[];continue}let a=await ut(o,{withFileTypes:!0});s[n]=n==="skills"?a.filter(i=>i.isDirectory()).map(i=>i.name).sort():a.filter(i=>i.isFile()&&i.name.endsWith(".md")).map(i=>i.name.replace(/\.md$/,"")).sort()}return s}var Ee="<!-- vesper:start -->",Te="<!-- vesper:end -->";function ys(){return[Ee,"@.claude/vesper/orchestrator.md","@.claude/vesper/orchestration.md","@.claude/vesper/context.md",Te].join(`
2
- `)}async function _s(e){let t=ht(e),s=ys(),n=new RegExp(`${Ee}[\\s\\S]*?${Te}`);if(!await h(t))return await q(Pe(t),{recursive:!0}),await E(t,`${s}
3
- `,"utf-8"),{created:!0,updated:!1};let o=await F(t,"utf-8");if(n.test(o)){let i=o.replace(n,s);return i!==o?(await E(t,i,"utf-8"),{created:!1,updated:!0}):{created:!1,updated:!1}}let a=`${s}
1
+ var Ps=(e,t)=>()=>(e&&(t=e(e=0)),t);import{access as Es,constants as Ts,stat as Ln}from"node:fs/promises";async function m(e){try{return await Es(e,Ts.F_OK),!0}catch{return!1}}var G=Ps(()=>{});import{Command as En}from"commander";import{readFileSync as Tn,existsSync as bn}from"node:fs";import{fileURLToPath as $n}from"node:url";import{dirname as Je,join as As}from"node:path";G();import{resolve as Cr,basename as Ar}from"node:path";import{spawn as Pr}from"node:child_process";import{confirm as ne,input as Er,number as Tr,select as br,checkbox as $r}from"@inquirer/prompts";import{readFile as b,writeFile as A,mkdir as le,readdir as js}from"node:fs/promises";import{join as y,dirname as q}from"node:path";import{homedir as it}from"node:os";import Ls from"strip-json-comments";import{fileURLToPath as bs}from"node:url";import{dirname as Oe,join as ie,resolve as $s}from"node:path";import{readdir as Os}from"node:fs/promises";import{existsSync as Is}from"node:fs";var Ms=bs(import.meta.url),Ds=Oe(Ms);function Rs(e){let t=e;for(;t!==Oe(t);){if(Is(ie(t,"package.json")))return t;t=Oe(t)}return $s(e,"..","..","..")}var Z=Rs(Ds),T=ie(Z,"assets"),Ye=ie(T,"core");function Ie(e){if(!e||typeof e!="string")throw new Error("Asset name is required");if(e.includes("..")||e.includes("/")||e.includes("\\"))throw new Error(`Invalid asset name: ${e}`)}var I={agents:{dir:"agents",destDir:"agents",extension:".agent.md",isFolder:!0},prompts:{dir:"prompts",destDir:"prompts",extension:".prompt.md",isFolder:!0},instructions:{dir:"instructions",destDir:"instructions",extension:".instructions.md",isFolder:!0},skills:{dir:"skills",destDir:"skills",extension:"",isFolder:!0}};async function ee(e){let t=I[e];if(!t)throw new Error(`Unknown asset type: ${e}`);let s=ie(T,t.dir);try{return(await Os(s,{withFileTypes:!0})).filter(o=>o.isDirectory()&&!o.name.startsWith(".")).map(o=>o.name)}catch{return[]}}function Xe(e,t){Ie(t);let s=I[e];if(!s)throw new Error(`Unknown asset type: ${e}`);return ie(T,s.dir,t)}function B(e){let t=it();return e.startsWith(t)?"~"+e.slice(t.length).replace(/\\/g,"/"):e.replace(/\\/g,"/")}var Vs=/node_modules\/(?:vesper-cli|vespercli)\/(.+)$/;function fe(e){if(typeof e!="string")return e;let t=e.match(Vs);return t?B(y(Z,t[1])):e}function Fs(e){return e==="vesper-cli"||e.startsWith("vesper-cli ")||e.endsWith("/vesper-cli")}var te={agents:"chat.agentFilesLocations",instructions:"chat.instructionsFilesLocations",prompts:"chat.promptFilesLocations",skills:"chat.agentSkillsLocations"},ce="chat.tools.terminal.autoApprove",ct="chat.tools.terminal.enableAutoApprove",De="chat.tools.autoApprove",v="chat.tools.eligibleForAutoApproval",lt="chat.agent.maxRequests",dt="chat.includeReferencedInstructions",ut="chat.customAgentInSubagent.enabled",pt="chat.agent.enabled",ft="github.copilot.chat.omitBaseAgentInstructions",gt="chat.mcp.discovery.enabled",mt="chat.mcp.autoStart",S="github.copilot.chat.additionalReadAccessPaths",M={maxRequests:300,terminalEnableAutoApprove:!0,omitBaseAgentInstructions:!0,enableMcpServer:!0},Ns=[lt,dt,ut,pt,ft,gt,mt,ct,ce,De,v],K=["vesper-indexing","sequential-thinking","memory"],Me=[".vesperrc",".mcp.json",".vscode/mcp.json",".vesper/index.db",".vesper/index.db-wal",".vesper/index.db-shm",".vesper/indexing-status.json",".claude/settings.local.json"];var Qe="# <!-- vesper:gitignore:start -->",Ze="# <!-- vesper:gitignore:end -->";async function ge(e){let t=y(e,".gitignore"),s=[Qe,...Me,Ze].join(`
2
+ `),r=new RegExp(`${Qe}[\\s\\S]*?${Ze}`),o="";try{o=await b(t,"utf-8")}catch(a){if(a.code!=="ENOENT")throw a;return await A(t,`${s}
3
+ `,"utf-8"),{created:!0,updated:!1}}if(r.test(o)){let a=o.replace(r,s);return a!==o?(await A(t,a,"utf-8"),{created:!1,updated:!0}):{created:!1,updated:!1}}let i=o.endsWith(`
4
+ `)?`
5
+ `:`
4
6
 
5
- ${o}`;return await E(t,a,"utf-8"),{created:!1,updated:!0}}function Ss(e){let t=new RegExp(`${Ee}[\\s\\S]*?${Te}\\n*`);return e.replace(t,"")}async function ve(e){let t=mt(e);await q(t,{recursive:!0});let s={orchestrator:"refreshed",orchestration:"skipped",context:"skipped"},n=w(Z,"vesper-orchestrator.md"),o=w(t,"orchestrator.md");await E(o,await F(n,"utf-8"),"utf-8");let a=w(t,"orchestration.md");await h(a)||(await E(a,await F(w(Z,"orchestration.md.tpl"),"utf-8"),"utf-8"),s.orchestration="created");let i=w(t,"context.md");await h(i)||(await E(i,await F(w(Z,"context.md.tpl"),"utf-8"),"utf-8"),s.context="created");let c=await _s(e);return s.claudeMd=c.created?"created":c.updated?"updated":"unchanged",s}async function xs(e){let t=K(e);try{let s=await F(t,"utf-8");return JSON.parse(s)}catch(s){return s.code==="ENOENT"?{mcpServers:{}}:{mcpServers:{}}}}async function As(e,t){let s=K(e);await q(Pe(s),{recursive:!0}),await E(s,JSON.stringify(t,null," "),"utf-8")}function Cs(e){return{"vesper-indexing":{command:"node",args:[V()],env:{VESPER_INDEX_ROOT:e}},"sequential-thinking":{command:"npx",args:["-y","@modelcontextprotocol/server-sequential-thinking"]},memory:{command:"npx",args:["-y","@modelcontextprotocol/server-memory"],env:{MEMORY_FILE_PATH:w(e,".vesper","memory.jsonl")}}}}async function ie(e,t=!0){let s=await xs(e);s.mcpServers||(s.mcpServers={});let n=Cs(e),o=Object.keys(n);if(t)for(let[a,i]of Object.entries(n))s.mcpServers[a]=i;else for(let a of o)delete s.mcpServers[a];return await As(e,s),{configured:t,mcpPath:K(e),servers:t?o:[]}}async function we(e){let t=me(e),s={};try{s=JSON.parse(await F(t,"utf-8"))}catch{s={}}s.permissions||(s.permissions={}),Array.isArray(s.permissions.allow)||(s.permissions.allow=[]);let n=["mcp__vesper-indexing__vesper_search","mcp__vesper-indexing__vesper_symbols","mcp__vesper-indexing__vesper_status","mcp__vesper-indexing__vesper_reindex","mcp__sequential-thinking__sequentialthinking","mcp__memory__create_entities","mcp__memory__create_relations","mcp__memory__add_observations","mcp__memory__delete_entities","mcp__memory__delete_observations","mcp__memory__delete_relations","mcp__memory__read_graph","mcp__memory__search_nodes","mcp__memory__open_nodes"],o=0;for(let a of n)s.permissions.allow.includes(a)||(s.permissions.allow.push(a),o+=1);return Ps(s),await q(Pe(t),{recursive:!0}),await E(t,JSON.stringify(s,null," "),"utf-8"),{configured:o,settingsPath:t}}var _t=".claude/vesper/",ks=`node -e "['orchestrator','orchestration','context'].forEach(n=>{try{process.stdout.write(require('fs').readFileSync('.claude/vesper/'+n+'.md','utf8')+'\\n\\n')}catch(e){}})"`;function Ps(e){e.hooks||(e.hooks={}),Array.isArray(e.hooks.SessionStart)||(e.hooks.SessionStart=[]),!e.hooks.SessionStart.some(s=>(s?.hooks||[]).some(n=>typeof n?.command=="string"&&n.command.includes(_t)))&&e.hooks.SessionStart.push({matcher:"clear",hooks:[{type:"command",command:ks}]})}function Es(e){Array.isArray(e?.hooks?.SessionStart)&&(e.hooks.SessionStart=e.hooks.SessionStart.filter(t=>!(t?.hooks||[]).some(s=>typeof s?.command=="string"&&s.command.includes(_t))),e.hooks.SessionStart.length===0&&delete e.hooks.SessionStart,e.hooks&&Object.keys(e.hooks).length===0&&delete e.hooks)}async function St(e,t){let s=await g(e);return s.claude={...s.claude,...t,updatedAt:new Date().toISOString()},await P(e,s),s.claude}async function ye(e){let t=mt(e);await pt(t,{recursive:!0,force:!0});let s=ht(e);if(await h(s)){let a=await F(s,"utf-8"),i=Ss(a);i.trim()?await E(s,i,"utf-8"):await pt(s,{force:!0})}await ie(e,!1);let n=me(e);if(await h(n))try{let a=JSON.parse(await F(n,"utf-8"));Es(a),await E(n,JSON.stringify(a,null," "),"utf-8")}catch{}let o=await g(e);delete o.claude,await P(e,o)}N();import{resolve as be,basename as js}from"node:path";import{rm as Vs}from"node:fs/promises";import{confirm as xt}from"@inquirer/prompts";import x from"picocolors";function Ts(e){console.log(`${x.green("\u2713")} ${e}`)}function bs(e){console.log(`${x.red("\u2717")} ${e}`)}function $s(e){console.log(`${x.yellow("!")} ${e}`)}function Os(e){console.log(`${x.cyan("\u2192")} ${e}`)}function Is(e){console.log(x.dim(e))}function Ms(e){return x.cyan(e)}function Ds(e){return x.bold(e)}function Fs(e){console.log(),console.log(x.bold(x.underline(e)))}function Ls(e,t=!1){let s=t?x.green("\u25CF"):x.dim("\u25CB");console.log(` ${s} ${e}`)}function Ns(){console.log(),console.log(x.bold(x.magenta("\u{1F3AF} Ready to use Vesper!"))),console.log(x.cyan(' In VS Code Chat, select "Vesper" from the agent dropdown')),console.log(x.cyan(" and start requesting!")),console.log()}function Rs(e){let t=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],s=0,n=null,o=e,a=()=>{let i=x.cyan(t[s]);process.stdout.write(`\r${i} ${o}`),s=(s+1)%t.length};return{start(){process.stdout.write(`
6
- `),n=setInterval(a,80),a()},update(i){o=i},stop(){n&&(clearInterval(n),n=null,process.stdout.write("\r"+" ".repeat(o.length+4)+"\r"))},succeed(i){this.stop(),console.log(`${x.green("\u2713")} ${i||o}`)},fail(i){this.stop(),console.log(`${x.red("\u2717")} ${i||o}`)}}}var r={success:Ts,error:bs,warn:$s,info:Os,dim:Is,formatPath:Ms,formatName:Ds,header:Fs,listItem:Ls,vesperTip:Ns,createSpinner:Rs};async function Us(e={}){let t=be(e.path||process.cwd());if(!(await g(t)).claude){r.warn("Claude Code target is not initialized in this workspace.");return}if(!e.yes&&!await xt({message:"Remove the Claude Code target from this project? (the shared plugin catalog at the user level is left untouched)",default:!1})){r.info("Reset cancelled.");return}await ye(t),console.log(),r.success("Claude Code target reset complete."),r.info("Removed: .claude/vesper/, CLAUDE.md guard block, .mcp.json entry, .vesperrc.claude"),r.info("Left untouched: the shared plugin catalog at ~/.claude/skills/vesper/")}function Ws(e){let t=new Set;for(let s of e)s.includes("/agents")&&t.add("Agents"),s.includes("/instructions")&&t.add("Instructions"),s.includes("/prompts")&&t.add("Prompts"),s.includes("/skills")&&t.add("Skills");return Array.from(t)}async function $e(e){let t=await g(e);await Xe(e);try{let n=await S(e);if(n[v]){let o=new Set(M),a=!1;for(let i of Object.keys(n[v]))o.has(i)||(delete n[v][i],a=!0);a&&await C(e,n)}}catch{}let s=be(e,".vesperrc");try{if(t.claude){let{writeFile:n}=await import("node:fs/promises");await n(s,JSON.stringify({paths:[],addedAt:null,workspaceType:null,settingsPath:null,claude:t.claude},null,2),"utf-8")}else await Vs(s,{force:!0})}catch{}}async function At(e={}){try{let t=be(e.path||process.cwd());await h(t)||(r.error(`Directory not found: ${r.formatPath(t)}`),process.exit(1));let s=e.target;if(!s){let c=await D(t);if(c.length===0){r.warn("Vesper is not initialized in this workspace.");return}c.length>1&&(r.error("Both Copilot and Claude targets are installed here \u2014 specify which to reset: --target copilot|claude"),process.exit(1)),s=c[0]}if(s==="claude")return await Us({...e,path:t});if(!await pe(t)){r.warn("Vesper is not initialized in this workspace.");return}let n=await Q(t);if(n.length===0){r.info("Nothing to reset.");return}let o=Ws(n);if(!e.yes&&!await xt({message:`Remove all Vesper assets (${o.join(", ")})?`,default:!1})){r.info("Reset cancelled.");return}let a=await g(t),i=await y(t);await $e(t),a.claude&&r.info("Claude Code target detected \u2014 kept its record in .vesperrc"),console.log(),r.success("Vesper reset complete."),a.workspaceType===k.WORKSPACE_FILE||i.type===k.WORKSPACE_FILE?r.info(`Cleaned: ${js(i.settingsPath)}`):r.info("Cleaned: .vscode/settings.json"),r.info("Reload VS Code to apply changes")}catch(t){if(t.name==="ExitPromptError"){console.log(),r.info("Reset cancelled.");return}r.error(`Reset failed: ${t.message}`),process.exit(1)}}var Ct=["copilot","claude"];function kt(e){return e==="claude"?"Claude Code":"GitHub Copilot"}async function zs(e){let t=await g(e),s=[];return Array.isArray(t.paths)&&t.paths.length>0&&s.push("copilot"),t.claude&&s.push("claude"),s}async function Xs(e,t){let s=await zs(t);if(e.target){let o=String(e.target).toLowerCase(),a=o==="all"?[...Ct]:o.split(",").map(i=>i.trim()).filter(Boolean);for(let i of a)Ct.includes(i)||(r.error(`Unknown target: ${i}. Valid targets: copilot, claude, all`),process.exit(1));return{selected:[...new Set(a)],installed:s}}return process.stdin.isTTY||(r.error("Non-interactive run without --target. Specify the platform(s), e.g. --target copilot,claude (or --target all)."),process.exit(1)),{selected:await Hs({message:s.length?"Platforms to set up (checked = installed; uncheck to remove):":"Which AI platform(s) is this workspace for?",choices:[{name:"GitHub Copilot (VS Code)",value:"copilot",checked:s.includes("copilot")},{name:"Claude Code (CLI / VS Code extension / JetBrains / desktop)",value:"claude",checked:s.includes("claude")}]}),installed:s}}async function Qs(e){return e?"":await Ys({message:"Name Vesper's Claude Code subagents/skills/commands:",choices:[{name:"Plain names (recommended \u2014 matches the Copilot catalog 1:1)",value:""},{name:'Prefix with "vesper-" (avoids collisions with other Claude Code kits)',value:"vesper-"}],default:""})}async function Zs(e,t={}){let s=t.yes||t.forceDefault,n=await Qs(s);console.log(),r.header("Installing Vesper for Claude Code"),console.log();let{pluginDir:o,counts:a}=await he({namePrefix:n,version:t.version||"0.0.0"});r.success(`Specialist catalog installed: ${o}`),r.info(` agents: ${a.agents}, commands: ${a.commands}, skills: ${a.skills}`);let i=await ve(e);r.success("Project files ready:"),r.info(` .claude/vesper/orchestrator.md (${i.orchestrator})`),r.info(` .claude/vesper/orchestration.md (${i.orchestration})`),r.info(` .claude/vesper/context.md (${i.context})`),r.info(` CLAUDE.md (${i.claudeMd})`);let c=await ie(e,!0);await we(e),r.success(`MCP servers configured: .mcp.json (${c.servers.join(", ")})`),await St(e,{pluginPath:B(),namePrefix:n,mcpConfigPath:K(e),settingsPath:me(e),installedAt:new Date().toISOString()})}async function en(e,t,s){console.log(),r.header("Configuring GitHub Copilot"),console.log();let n=await ot(e);await Ze(e,{maxRequests:s.maxRequests,omitBaseAgentInstructions:s.omitBaseAgentInstructions});let o=await Qe(e,s.terminalEnableAutoApprove),a=!1;return s.enableMcpServer&&(a=(await ae(e,!0)).configured,await it(e)),r.success("Core assets ensured: agents, prompts, instructions, skills"),r.info(`Max agent requests: ${s.maxRequests}`),o.configured>0?r.info(`Terminal auto-approval: ${o.configured} safe commands configured`):s.terminalEnableAutoApprove===!1&&r.info("Terminal auto-approval: disabled"),a&&(r.info("MCP servers: vesper-indexing, sequential-thinking, memory (.vscode/mcp.json)"),r.info("MCP tools auto-approval: vesper-indexing + context7 + sequential-thinking + memory")),n.workspaceType===k.WORKSPACE_FILE?r.info(`Settings added to: ${qs(t.settingsPath)}`):r.info("Settings added to: .vscode/settings.json"),r.info("Tracking file: .vesperrc"),{mcpConfigured:a}}async function tn(e,t){let s=await Ye(e);if(!s.found)return{migrated:!1,from:null};let{paths:n}=s;console.log(),r.warn(`Found .vesperrc in nested folder${n.length>1?"s":""}:`);for(let{folderPath:i}of n)r.info(` \u2192 ${i}`);console.log();let o=n[0],a=!0;if(t||(a=await ee({message:"Migrate .vesperrc to workspace level? (recommended for multi-root workspaces)",default:!0})),a){let i=await He(e,o.vesperrcPath,o.tracking);if(i.success){if(r.success("Migrated .vesperrc to workspace level"),r.info(` From: ${o.vesperrcPath}`),r.info(` To: ${i.newPath}`),n.length>1){let{unlink:c}=await import("node:fs/promises");for(let d=1;d<n.length;d++)try{await c(n[d].vesperrcPath),r.info(` Removed: ${n[d].vesperrcPath}`)}catch{}}return console.log(),{migrated:!0,from:o.folderPath}}}else r.info("Migration skipped. .vesperrc will remain in nested folder."),console.log();return{migrated:!1,from:null}}async function sn(e){let{migrated:t,changed:s}=await rt(e);if(!t)return;let n=(a,i)=>`${a} ${i}${a>1?"s":""}`,o=[];s.assetPaths&&o.push(n(s.assetPaths,"asset path")),s.readAccess&&o.push(n(s.readAccess,"read-access path")),s.commandKeys&&o.push(n(s.commandKeys,"stale command")),s.trackingPaths&&o.push(n(s.trackingPaths,"tracked path")),s.mcpArgs&&o.push("MCP server path"),console.log(),r.info("Detected a workspace set up under the older `vesper-cli` package \u2014 migrating install paths."),r.success(`Migrated: ${o.join(", ")}`),console.log()}async function nn(e,t){let s=e;return t||(s=await Ks({message:"Workspace root directory:",default:s})),Gs(s)}async function rn(e,t,s){let n=[];for(let o of t){let a=kt(o),i=s;if(s||(i=await ee({message:`${a} is installed but was unchecked. Remove it from this project?`,default:!1})),!i){r.info(`Kept ${a}.`);continue}o==="claude"?await ye(e):await $e(e),n.push(o),r.success(`Removed ${a} from this project.`)}return n}async function on(e){if(e)return{maxRequests:$.maxRequests,terminalEnableAutoApprove:$.terminalEnableAutoApprove,omitBaseAgentInstructions:$.omitBaseAgentInstructions,enableMcpServer:$.enableMcpServer};console.log(),r.info("Configure VS Code Chat settings:");let t=await Js({message:"Max agent requests per session (chat.agent.maxRequests):",default:$.maxRequests,min:1,max:1e3}),s=await ee({message:"Controls whether terminal commands are automatically approved. Enable terminal auto-approval? (chat.tools.terminal.enableAutoApprove)",default:$.terminalEnableAutoApprove});s&&r.info("Terminal auto-approval enabled with safe command whitelist");let n=await ee({message:"Omit base agent instructions for custom agents? (github.copilot.chat.omitBaseAgentInstructions)",default:$.omitBaseAgentInstructions}),o=await ee({message:"Enable vesper-indexing MCP server for fast code search?",default:$.enableMcpServer});return{maxRequests:t||$.maxRequests,terminalEnableAutoApprove:s,omitBaseAgentInstructions:n,enableMcpServer:o}}async function an(e,t=!1){let s=V().replace("index.js","cli-index.js");if(!await h(s))return{success:!1,error:"MCP server not built"};t&&(console.log(),r.info("Starting workspace indexing..."));let n=t?null:r.createSpinner("Indexing workspace...");return n&&n.start(),new Promise(o=>{let a=Bs("node",[s,e],{stdio:["ignore","pipe","pipe"],env:{...process.env}}),i="",c=0;a.stderr.on("data",d=>{let l=d.toString().trim(),u=l.match(/Indexed (\d+) files/);if(u&&(c=parseInt(u[1],10),n&&n.update(`Indexing workspace... ${c} files`)),t&&l)for(let p of l.split(`
7
- `))p.trim()&&r.info(p.replace("[vesper-indexing] ",""))}),a.stdout.on("data",d=>{i+=d.toString()}),a.on("close",d=>{try{let l=JSON.parse(i.trim());l.success?n?n.succeed(`Workspace indexed: ${l.filesIndexed} files`):r.success(`Workspace indexed: ${l.filesIndexed} files`):n?n.fail(`Indexing failed: ${l.error}`):r.error(`Indexing failed: ${l.error}`),o(l)}catch{d===0?(n?n.succeed(`Workspace indexed: ${c} files`):r.success(`Workspace indexed: ${c} files`),o({success:!0,filesIndexed:c})):(n?n.fail("Indexing failed"):r.error("Indexing failed"),o({success:!1,error:"Unknown error"}))}}),a.on("error",d=>{n?n.fail(`Indexing failed: ${d.message}`):r.error(`Indexing failed: ${d.message}`),o({success:!1,error:d.message})})})}function cn({copilot:e,claude:t,indexingResult:s}){console.log(),r.success("Vesper is ready."),s?.success?r.info(`Code index built: ${s.filesIndexed} files.`):s?.error&&r.info("Code index will be built on first MCP server start."),console.log(),r.header("Next Steps"),console.log(),e&&(r.info("GitHub Copilot \u2014 reload VS Code to activate Vesper:"),r.info(' Cmd+Shift+P (macOS) / Ctrl+Shift+P (Windows/Linux) \u2192 "Developer: Reload Window"')),t&&(r.info("Claude Code \u2014 open a session in this workspace; the orchestrator"),r.info(" activates automatically via CLAUDE.md.")),console.log(),e&&r.vesperTip()}async function Pt(e={}){try{let t=e.yes||e.forceDefault,s=await nn(e.path||process.cwd(),t);await h(s)||(r.error(`Directory not found: ${r.formatPath(s)}`),process.exit(1));let n=await y(s);n.type===k.WORKSPACE_FILE&&await tn(s,t),await sn(s);let{selected:o,installed:a}=await Xs(e,s),i=a.filter(f=>!o.includes(f));if(o.length===0&&i.length===0){r.info("No platforms selected. Nothing to do.");return}if(!t&&a.length===0&&o.length>0&&!await ee({message:`Set up ${o.map(kt).join(" + ")} in ${s}?`,default:!0})){r.info("Initialization cancelled.");return}i.length>0&&await rn(s,i,t);let c=o.includes("copilot"),d=o.includes("claude"),l=null;c&&(l=await on(t)),c&&await en(s,n,l),d&&await Zs(s,e);let u=c&&l?.enableMcpServer||d,p=null;u&&(p=await an(s,!0)),cn({copilot:c,claude:d,indexingResult:p})}catch(t){if(t.name==="ExitPromptError"){console.log(),r.info("Initialization cancelled.");return}r.error(`Initialization failed: ${t.message}`),process.exit(1)}}N();import{resolve as Tt,basename as ln}from"node:path";import{checkbox as bt,select as dn}from"@inquirer/prompts";var Et={agents:"agents",prompts:"commands",skills:"skills"};async function pn(e,t){let s=await D(e);if(s.length===1)return s[0];s.length===0&&(r.warn('Vesper is not initialized in this workspace. Run "vespercli init" first.'),process.exit(0)),r.error(`Both Copilot and Claude targets are installed here \u2014 specify which to ${t}: --target copilot|claude`),process.exit(1)}async function un(e={}){let t=Tt(e.path||process.cwd());(!e.type||!e.name)&&(r.error("Usage: vesper add <type> <name> --target claude"),r.info("Types: agents, prompts (installed as slash commands), skills"),process.exit(1));let s=Et[e.type];s||(r.error(`Unknown asset type for --target claude: ${e.type}`),r.info(`Available types: ${Object.keys(Et).join(", ")}`),process.exit(1));let o=(await g(t)).claude?.namePrefix??"";try{let a=await wt(s,e.name,{namePrefix:o});r.success(`Added ${e.type}/${e.name} to the Claude plugin catalog as "${a.installedAs}"`)}catch(a){r.error(a.message),process.exit(1)}}var ce=["agents","prompts","instructions"];async function Oe(e,t){let s=await Q(e);return(await Y(t)).filter(o=>{let a=G(t,o);return!s.includes(a.path)})}async function fn(e){let t=[];for(let i of ce){let c=await Oe(e,i);c.length>0&&t.push({name:`${i.charAt(0).toUpperCase()+i.slice(1)} (${c.length} available)`,value:i})}if(t.length===0)return r.info("All extended assets are already added."),[];let s=await dn({message:"Select asset type:",choices:t}),o=(await Oe(e,s)).map(i=>({name:i,value:i,checked:!1}));return(await bt({message:`Select ${s} to add:`,choices:o})).map(i=>({type:s,name:i}))}async function $t(e={}){try{let t=Tt(e.path||process.cwd());if(await h(t)||(r.error(`Directory not found: ${r.formatPath(t)}`),process.exit(1)),(e.target||await pn(t,"add"))==="claude")return await un({...e,path:t});if(!await pe(t)){r.warn('Vesper is not initialized. Run "vespercli init" first.');return}let n=[];if(e.type&&e.name){if(e.type==="skills"){r.info("Skills are automatically added during init.");return}ce.includes(e.type)||(r.error(`Unknown asset type: ${e.type}`),r.info(`Available types: ${ce.join(", ")}`),process.exit(1));let l=await Y(e.type);l.includes(e.name)||(r.error(`Asset not found: ${e.name}`),r.info(`Available ${e.type}: ${l.join(", ")||"none"}`),process.exit(1)),n=[{type:e.type,name:e.name}]}else if(e.type){if(e.type==="skills"){r.info("Skills are automatically added during init.");return}ce.includes(e.type)||(r.error(`Unknown asset type: ${e.type}`),r.info(`Available types: ${ce.join(", ")}`),process.exit(1));let l=await Oe(t,e.type);if(l.length===0){r.info(`All ${e.type} are already added.`);return}let u=l.map(f=>({name:f,value:f,checked:!1})),p=await bt({message:`Select ${e.type} to add:`,choices:u});if(p.length===0){r.info("Nothing selected.");return}n=p.map(f=>({type:e.type,name:f}))}else if(n=await fn(t),n.length===0){r.info("Nothing selected.");return}let o=n.map(({type:l,name:u})=>G(l,u)),{added:a,skipped:i,workspaceType:c}=await ze(t,o),d=n.filter(l=>l.type==="agents"&&a.includes(G(l.type,l.name).path));for(let{name:l}of d)Ce[l]&&(await ct(t,l),r.info(` Added MCP tools auto-approval for agent: ${l}`));if(a.length>0){let l=await y(t);console.log(),r.success(`Added ${a.length} asset(s):`);for(let{type:u,name:p}of n.filter(f=>a.includes(G(f.type,f.name).path)))r.info(` ${u}/${p}`);c===k.WORKSPACE_FILE&&r.info(`
8
- Updated: ${ln(l.settingsPath)}`),r.info(`
9
- Reload VS Code to apply changes`)}else i.length>0&&r.info("All selected assets are already added.")}catch(t){if(t.name==="ExitPromptError"){console.log(),r.info("Cancelled.");return}r.error(`Add failed: ${t.message}`),process.exit(1)}}N();import{resolve as It,join as gn}from"node:path";import{readdir as mn}from"node:fs/promises";import L from"picocolors";async function Ot(e={}){let t=It(e.path||process.cwd()),s=await g(t);if(console.log(),console.log(L.bold("Claude Code target")),!s.claude){console.log(),r.warn('Not initialized for Claude Code. Run "vesper init --target claude" first.'),console.log();return}let n=s.claude.pluginPath||B();console.log(L.dim(`Plugin catalog: ${n}`));let o=await yt();for(let[a,i]of Object.entries(o))console.log(),console.log(L.bold(a.charAt(0).toUpperCase()+a.slice(1))),i.length===0?console.log(L.dim(" (none installed)")):i.forEach(c=>console.log(` ${c}`));console.log(),console.log(L.bold("Project files")),console.log(" CLAUDE.md, .claude/vesper/{orchestrator,orchestration,context}.md, .mcp.json, .claude/settings.json"),console.log()}async function hn(e,t,s=!1){try{let n=await mn(e,{withFileTypes:!0});return s||t.dir==="skills"?n.filter(a=>a.isDirectory()&&!a.name.startsWith(".")).map(a=>a.name):n.filter(a=>a.isFile()&&a.name.endsWith(t.extension)).map(a=>a.name.replace(t.extension,""))}catch{return[]}}async function Mt(e={}){try{let t=It(e.path||process.cwd());await h(t)||(r.error(`Directory not found: ${r.formatPath(t)}`),process.exit(1));let s=await D(t);if(e.target==="claude")return await Ot({...e,path:t});if(!e.target){if(s.length===0){console.log(),r.warn('Vesper is not initialized. Run "vespercli init" first.'),console.log();return}if(s.length===1&&s[0]==="claude")return await Ot({...e,path:t});s.includes("claude")&&r.info("Claude Code target is also installed here \u2014 run `vespercli list --target claude` to see it.")}let n=await Q(t);e.type&&!b[e.type]&&(r.error(`Unknown asset type: ${e.type}`),r.info(`Valid types: ${Object.keys(b).join(", ")}`),process.exit(1));let o=e.type?[e.type]:Object.keys(b);console.log(),console.log(L.bold("Assets"));for(let a of o){let i=b[a],c=a.charAt(0).toUpperCase()+a.slice(1);if(a==="skills"){let f=nt("skills");if(n.includes(f.path)){let m=await Y("skills");console.log(),console.log(L.bold(`${c}`)),console.log(` ${m.length} skills enabled ${L.dim("(all)")}`)}continue}let d=gn(Le,i.dir),l=await hn(d,i,!1),p=(await Y(a)).filter(f=>{let m=G(a,f);return n.includes(m.path)});(l.length>0||p.length>0)&&(console.log(),console.log(L.bold(`${c}`)),l.forEach(f=>{console.log(` ${f} ${L.dim("(core)")}`)}),p.forEach(f=>{console.log(` ${f}`)}))}console.log()}catch(t){r.error(`List failed: ${t.message}`),process.exit(1)}}import{readFileSync as vn,existsSync as wn}from"node:fs";import{join as yn}from"node:path";var Dt="catalog.md",_n="mthanhtran",Sn="vesper",xn="main";function An(){return`https://raw.githubusercontent.com/${_n}/${Sn}/${xn}/assets/${Dt}`}function Cn(){let e=yn(J,"assets",Dt);return wn(e)?vn(e,"utf-8"):null}async function kn(){try{let e=An(),t=await fetch(e);return t.ok?t.text():null}catch{return null}}async function Pn(){let e=await kn();if(e)return e;let t=Cn();if(t)return t;throw new Error("Catalog not available from remote or local")}async function Ft(){try{let e=await Pn();console.log(e)}catch(e){console.error(`Error loading catalog: ${e.message}`),process.exit(1)}}N();import{resolve as En,join as Nt}from"node:path";import{stat as Tn,readFile as Rt}from"node:fs/promises";import"@inquirer/prompts";import W from"picocolors";async function Ie(e){let t=await g(e);if(console.log(),r.header("vesper-indexing MCP Server (Claude Code target)"),console.log(),!t.claude){r.info("Claude Code target is not initialized. Run `vesper init --target claude` first.");return}let s=K(e),n=!1;if(await h(s))try{n=!!JSON.parse(await Rt(s,"utf-8")).mcpServers?.["vesper-indexing"]}catch{n=!1}r.info(`Configured: ${n?"\u2713 yes":"\u2717 no"} (${s})`),r.info(`Server built: ${await Vt()?"\u2713 yes":"\u2717 no"}`);let o=Me(e);r.info(`Index exists: ${await h(o)?"\u2713 yes":"\u2717 no"} (shared with the Copilot target if both are installed)`)}async function te(e,t=!0){await ie(e,t),t&&await we(e),r.success(`Claude Code target: vesper-indexing ${t?"enabled":"disabled"} in .mcp.json`)}function Me(e){return Nt(e,".vesper","index.db")}function bn(e){return Nt(e,".vesper","indexing-status.json")}async function jt(e){let t=bn(e);try{let s=await Rt(t,"utf-8");return JSON.parse(s)}catch{return null}}async function Vt(){let e=V();return await h(e)}async function $n(e){try{let t=await Tn(e),s=t.size,n=`${s} bytes`;return s>1024*1024?n=`${(s/(1024*1024)).toFixed(2)} MB`:s>1024&&(n=`${(s/1024).toFixed(1)} KB`),{dbSize:n,lastModified:t.mtime.toISOString()}}catch{return null}}async function Lt(e,t=!1){let s=await at(e),n=await Vt(),o=Me(e),a=await h(o),i=await jt(e);if(console.log(),r.header("vesper-indexing MCP Server"),console.log(),r.info(`Configured: ${s?"\u2713 yes":"\u2717 no"}`),r.info(`Server built: ${n?"\u2713 yes":"\u2717 no"}`),r.info(`Index exists: ${a?"\u2713 yes":"\u2717 no"}`),i)if(console.log(),i.status==="indexing")if(t){await On(e,i);return}else{let c=i.startedAt?Math.round((Date.now()-new Date(i.startedAt).getTime())/1e3):0;r.info(W.yellow("\u27F3 Indexing in progress...")),r.info(` Files processed: ${W.cyan(i.filesProcessed)}`),r.info(` Elapsed: ${W.dim(`${c}s`)}`),console.log(),r.info("Use --watch to follow indexing progress until completion")}else i.status==="error"&&(r.error(`Indexing error: ${i.error}`),r.info(` Files processed before error: ${i.filesProcessed}`));if(!s){console.log(),r.info("Run `vespercli init` to configure the MCP server");return}if(!n){console.log(),r.warn("MCP server not built. Run: cd src/mcp/vesper-indexing && npm install && npm run build");return}if(a&&!i){let c=await $n(o);c&&(console.log(),r.info(`Index size: ${c.dbSize}`),r.info(`Last modified: ${c.lastModified}`)),r.vesperTip()}else!a&&!i&&(console.log(),r.info("Index not yet created. It will be built when VS Code loads the MCP server."),console.log())}async function On(e,t){let s=r.createSpinner(`Indexing... ${t.filesProcessed} files processed`);s.start();let n=500,o=30*60*1e3,a=Date.now();return new Promise(i=>{let c=async()=>{let d=await jt(e);if(!d||d.status!=="indexing"){d?.status==="error"?s.fail(`Indexing failed: ${d.error}`):(s.succeed(`Indexing complete! ${d?.filesProcessed||"All"} files indexed`),r.info(`
10
- \u2192 Reload VS Code to update MCP tools with the new index`),r.vesperTip()),i();return}let l=d.startedAt?Math.round((Date.now()-new Date(d.startedAt).getTime())/1e3):0;if(s.update(`Indexing... ${d.filesProcessed} files processed (${l}s)`),Date.now()-a>o){s.fail("Indexing watch timed out (30 minutes)"),i();return}setTimeout(c,n)};setTimeout(c,n)})}async function In(e,t=!1){let s=Me(e);if(!await h(s))r.info("No index exists. It will be built when VS Code loads the MCP server.");else if(t){let{unlink:o}=await import("node:fs/promises");await o(s),r.success("Index cleared. Reload VS Code to rebuild.")}else r.info("Incremental reindex happens automatically when files change."),r.info("Use --full to clear and rebuild the entire index.")}async function Mn(e){let t=await ae(e,!0);t.configured&&(r.success("MCP server enabled"),r.info(`Config: ${t.mcpPath}`),r.info("Reload VS Code to start the server"))}async function Dn(e){await ae(e,!1),r.success("MCP server disabled"),r.info("Reload VS Code to apply changes")}async function Ut(e){let t=await y(e),s=await g(e,t);if(!Array.isArray(s.paths))return[];let n=[];for(let o of s.paths){let a=o.match(/agents\/([^/]+)\/?$/);a&&MCP_TOOLS_BY_AGENT[a[1]]&&n.push(a[1])}return n}async function Fn(e){let t=await y(e),s=await g(e,t),n=await S(e,t),o=await Ut(e),a=n[v]||{},i=new Set(M),c=[],d=[],l=!1;n[v]||(n[v]={});for(let p of M)a[p]||(n[v][p]=!0,c.push(p),l=!0);for(let p of o){let f=MCP_TOOLS_BY_AGENT[p]||[];for(let m of f)a[m]||(n[v][m]=!0,c.push(m),l=!0)}let u=new Set;for(let p of o)for(let f of MCP_TOOLS_BY_AGENT[p]||[])u.add(f);for(let p of Object.keys(a)){if(i.has(p))continue;let f=!1;for(let[m,T]of Object.entries(MCP_TOOLS_BY_AGENT))if(T.includes(p)){f=!0;break}f&&!u.has(p)&&(delete n[v][p],d.push(p),l=!0)}if(s.mcp=s.mcp||{},s.mcp.syncedAt=new Date().toISOString(),s.mcp.approvedAgents=o,s.mcp.toolCount=Object.keys(n[v]).length,l&&await C(e,n),await P(e,s),console.log(),r.header("MCP Tools Sync"),console.log(),c.length===0&&d.length===0)r.success("Already in sync");else{if(c.length>0){r.success(`Added ${c.length} tool(s)`);let p=c.filter(f=>i.has(f));p.length>0&&r.info(` Core: ${p.length} tools`);for(let f of o){let m=c.filter(T=>(MCP_TOOLS_BY_AGENT[f]||[]).includes(T));m.length>0&&r.info(` ${f}: ${m.length} tools`)}}d.length>0&&r.info(`Removed ${d.length} orphaned tool(s)`)}r.info(`
11
- Total approved tools: ${s.mcp.toolCount}`),o.length>0&&r.info(`Agents with tools: ${o.join(", ")}`),l&&r.info(`
12
- Reload VS Code to apply changes`)}async function Ln(e){let t=await y(e),s=await g(e,t),o=(await S(e,t))[v]||{},a=Object.keys(o).length,i=await Ut(e);console.log(),r.header("MCP Tool Approval Status"),console.log();let c=M.filter(u=>o[u]);if(r.info(`Core tools: ${c.length}/${M.length} approved`),i.length>0){console.log(),r.info("Agent tools:");for(let u of i){let p=MCP_TOOLS_BY_AGENT[u]||[],f=p.filter(T=>o[T]),m=f.length===p.length?W.green("\u2713"):W.yellow("\u26A0");r.info(` ${m} ${u}: ${f.length}/${p.length} approved`)}}let d=[...M];for(let u of i)d.push(...MCP_TOOLS_BY_AGENT[u]||[]);let l=d.filter(u=>!o[u]);console.log(),r.info(`Total approved: ${a} tools`),l.length>0?(console.log(),r.warn(`${l.length} tools missing approval`),r.info("Run `vespercli mcp sync` to fix")):s.mcp?.syncedAt&&r.info(`Last synced: ${s.mcp.syncedAt}`)}async function Nn(e,t){t||(r.error("Server name required. Usage: vespercli mcp add <server>"),r.info("Available servers: clickup, vesper-indexing, sequential-thinking"),process.exit(1)),console.log(),r.header("Add MCP Server"),console.log();let s=await lt(e,t);if(!s.added){s.error==="Already configured"?r.info(`MCP server '${t}' is already configured`):(r.error(s.error),process.exit(1));return}r.success(`Added MCP server: ${t}`),s.tools.length>0&&r.info(`Approved ${s.tools.length} tool(s) for auto-execution`),r.info(`
13
- Reload VS Code to activate the MCP server`)}async function Rn(e,t){t||(r.error("Server name required. Usage: vespercli mcp remove <server>"),process.exit(1)),console.log(),r.header("Remove MCP Server"),console.log();let s=await dt(e,t);if(!s.removed){r.info(`MCP server '${t}' is not configured`);return}r.success(`Removed MCP server: ${t}`),s.tools.length>0&&r.info(`Removed ${s.tools.length} tool(s) from auto-approval`),r.info(`
14
- Reload VS Code to deactivate the MCP server`)}async function jn(e){let t=await y(e),s=await g(e,t),n=await U(e);console.log(),r.header("MCP Servers"),console.log();let o=s.mcp?.servers||[],a=Object.keys(n.servers||{});r.info("Available servers:");for(let[c,d]of Object.entries(oe)){let u=a.includes(c)?W.green("\u2713"):W.dim("\u25CB"),p=d.tools?.length||0;r.info(` ${u} ${c} (${p} tools)`)}let i=a.filter(c=>!oe[c]);if(i.length>0){console.log(),r.info("Custom servers:");for(let c of i)r.info(` ${W.blue("\u25C6")} ${c}`)}console.log(),r.info(`Installed: ${a.length} server(s)`)}async function Wt(e,t,s={}){let n=En(s.path||process.cwd());await h(n)||(r.error(`Directory not found: ${n}`),process.exit(1));let o=await D(n),a=s.target?[s.target]:o.length?o:["copilot"],i=a.includes("copilot"),c=a.includes("claude");if(c&&!i)switch(e){case"enable":return await te(n,!0);case"disable":return await te(n,!1);case"sync":return await te(n,!0);case"status":default:return await Ie(n)}let d=i&&c;switch(e){case"status":await Lt(n,s.watch),d&&await Ie(n);break;case"add":await Nn(n,t);break;case"remove":await Rn(n,t);break;case"list":await jn(n);break;case"reindex":await In(n,s.full);break;case"enable":await Mn(n),d&&await te(n,!0);break;case"disable":await Dn(n),d&&await te(n,!1);break;case"sync":await Fn(n),d&&await te(n,!0);break;case"approve":await Ln(n);break;default:await Lt(n,s.watch),d&&await Ie(n)}}import{resolve as Vn}from"node:path";async function qt(e,t,s,n={}){let o=Vn(n.path||process.cwd());if(!e){Gt();return}switch(e){case"add":await Un(o,t,s);break;case"remove":await Wn(o,t,s);break;case"list":await Gn(o,t);break;default:r.error(`Unknown subcommand: ${e}`),Gt()}}async function Un(e,t,s){if(!t){r.error("Setting key required"),r.info("Usage: vespercli settings add <setting-key> <value>");return}switch(t){case"github.copilot.chat.additionalReadAccessPaths":case"additionalReadAccessPaths":case"read-access":if(!s){r.error("Path value required"),r.info("Usage: vespercli settings add read-access <path>");return}let n=await et(e,s);r.success(`Added "${s}" to additional read access paths`),r.info(`Current paths: ${n.length>0?n.join(", "):"(none)"}`);break;default:r.error(`Unknown setting: ${t}`),r.info("Supported settings:"),r.info(" - read-access (github.copilot.chat.additionalReadAccessPaths)")}}async function Wn(e,t,s){if(!t){r.error("Setting key required"),r.info("Usage: vespercli settings remove <setting-key> <value>");return}switch(t){case"github.copilot.chat.additionalReadAccessPaths":case"additionalReadAccessPaths":case"read-access":if(!s){r.error("Path value required"),r.info("Usage: vespercli settings remove read-access <path>");return}let n=await tt(e,s);r.success(`Removed "${s}" from additional read access paths`),r.info(`Current paths: ${n.length>0?n.join(", "):"(none)"}`);break;default:r.error(`Unknown setting: ${t}`),r.info("Supported settings:"),r.info(" - read-access (github.copilot.chat.additionalReadAccessPaths)")}}async function Gn(e,t){if(!t){r.info("Managed settings:"),r.info(" - read-access (github.copilot.chat.additionalReadAccessPaths)"),r.info(""),r.info("Use: vespercli settings list <setting-key>");return}switch(t){case"github.copilot.chat.additionalReadAccessPaths":case"additionalReadAccessPaths":case"read-access":let s=await st(e);r.info(`${_}:`),s.length===0?r.info(" (empty)"):s.forEach(n=>r.info(` - ${n}`));break;default:r.error(`Unknown setting: ${t}`),r.info("Supported settings:"),r.info(" - read-access (github.copilot.chat.additionalReadAccessPaths)")}}function Gt(){r.info("Usage: vespercli settings <subcommand> [setting-key] [value]"),r.info(""),r.info("Subcommands:"),r.info(" add <setting-key> <value> Add a value to an array setting"),r.info(" remove <setting-key> <value> Remove a value from an array setting"),r.info(" list [setting-key] List current values"),r.info(""),r.info("Supported settings:"),r.info(" read-access github.copilot.chat.additionalReadAccessPaths"),r.info(""),r.info("Examples:"),r.info(" vespercli settings add read-access /path/to/external/repo"),r.info(" vespercli settings remove read-access /path/to/external/repo"),r.info(" vespercli settings list read-access")}N();import{resolve as Bt}from"node:path";async function qn(e={}){let t=Bt(e.path||process.cwd()),s=await g(t);if(!s.claude){r.warn('Claude Code target is not initialized. Run "vesper init --target claude" first.');return}console.log(),r.info("Refreshing Claude Code plugin catalog and orchestrator playbook...");let{pluginDir:n,counts:o}=await he({namePrefix:s.claude.namePrefix||"",version:e.version||"0.0.0"});r.success(`Plugin catalog refreshed: ${n}`),r.info(` agents: ${o.agents}, commands: ${o.commands}, skills: ${o.skills}`);let a=await ve(t);r.success(`Orchestrator playbook refreshed (.claude/vesper/orchestrator.md: ${a.orchestrator})`),r.info("Team roster (.claude/vesper/orchestration.md) and project context (.claude/vesper/context.md) are left alone \u2014 they belong to this project.")}async function Kt(e={}){try{let t=Bt(e.path||process.cwd());await h(t)||(r.error(`Directory not found: ${r.formatPath(t)}`),process.exit(1));let s=e.target?[e.target]:await D(t);if(s.length===0){r.warn('Vesper is not initialized. Run "vespercli init" first.');return}s.includes("claude")&&await qn({...e,path:t}),s.includes("copilot")&&(console.log(),r.info("Copilot assets are linked from the package, not copied."),r.info("Update the vesper package to get the latest assets:"),r.dim(" npm update -g @mthanh/vespercli"),console.log())}catch(t){r.error(`Update failed: ${t.message}`),process.exit(1)}}var Hn=Yn(import.meta.url),zn=De(Hn);function Xn(e){let t=e;for(;t!==De(t);){let s=Jt(t,"package.json");if(Jn(s))return s;t=De(t)}return Jt(e,"..","..","package.json")}var Qn=Xn(zn),Fe=JSON.parse(Kn(Qn,"utf-8")),I=new Bn;I.name("vespercli").description("Vesper VS Code Agent Suite \u2014 manage GitHub Copilot agents, prompts, instructions, and skills").version(Fe.version,"-v, --version","Output the current version");I.command("init").description("Initialize vesper for one or more platforms (GitHub Copilot and/or Claude Code) in this workspace").option("-p, --path <path>","Workspace root directory",process.cwd()).option("-y, --yes","Skip follow-up prompts (not the platform selection)").option("-f, --force","Force re-initialization (skips follow-up prompts)").option("--force-default","Use all default values for follow-up prompts (not the platform selection)").option("--target <targets>","Platform(s) to set up: copilot, claude, a comma list (copilot,claude), or all. Multi-select prompt if omitted.").action(e=>Pt({...e,version:Fe.version}));I.command("add").description("Add extended assets \u2014 to VS Code settings (Copilot) or the Claude Code plugin catalog. Target is auto-detected from the workspace when omitted.").argument("[type]","Asset type (agents, prompts, instructions, skills)").argument("[name]","Asset name (specific asset to add)").option("--path <path>","Workspace root directory",process.cwd()).option("--target <target>","Install target: copilot or claude (auto-detected if omitted)").action((e,t,s)=>$t({type:e,name:t,...s}));I.command("reset").description("Remove the Vesper install \u2014 Copilot settings or the Claude Code target. Target is auto-detected from the workspace when omitted.").option("--path <path>","Workspace root directory",process.cwd()).option("-y, --yes","Skip confirmation prompts").option("--target <target>","Install target: copilot or claude (auto-detected if omitted)").action(At);I.command("list").alias("ls").description("List enabled assets").argument("[type]","Filter by asset type (agents, prompts, instructions, skills)").option("--path <path>","Workspace root directory",process.cwd()).option("--target <target>","Install target: copilot or claude (omit to see all installed targets)").action((e,t)=>Mt({type:e,...t}));I.command("update").description("Refresh installed targets \u2014 the Claude Code plugin catalog + orchestrator playbook, and/or the Copilot package-link note. Auto-detected from the workspace when omitted.").option("--path <path>","Workspace root directory",process.cwd()).option("--target <target>","Install target: copilot or claude (auto-detected if omitted)").action(e=>Kt({...e,version:Fe.version}));I.command("catalog").description("Show the Vesper catalog (agents, dependencies, requirements)").action(Ft);I.command("mcp").description("Manage MCP servers and tool auto-approval").argument("[subcommand]","Subcommand: status, add, remove, list, sync, approve, reindex, enable, disable").argument("[argument]","Argument for subcommand (e.g., server name for add/remove)").option("--path <path>","Workspace root directory",process.cwd()).option("--full","Full reindex (clears existing index)").option("-w, --watch","Watch indexing progress until completion").option("--target <target>","Install target: copilot, claude, or omit for all installed targets").action((e,t,s)=>Wt(e,t,s));I.command("settings").description("Manage VS Code settings").argument("[subcommand]","Subcommand: add, remove, list").argument("[setting-key]","Setting key (e.g., read-access)").argument("[value]","Value to add/remove").option("--path <path>","Workspace root directory",process.cwd()).action((e,t,s,n)=>qt(e,t,s,n));I.addHelpText("after",`
7
+ `;return await A(t,`${o}${i}${s}
8
+ `,"utf-8"),{created:!1,updated:!0}}async function me(e){let{execFile:t}=await import("node:child_process"),{promisify:s}=await import("node:util"),r=s(t),o=async d=>{try{let{stdout:l}=await r("git",d,{cwd:e});return l}catch{return null}},i=await o(["rev-parse","--is-inside-work-tree"]);if(i===null||i.trim()!=="true")return[];let a=await o(["ls-files","-z","--",...Me]);if(!a)return[];let c=new Set(a.split("\0").filter(Boolean));return Me.filter(d=>c.has(d))}var et="Vesper: worktree bootstrap";async function ht(e){let t=y(e,".vscode","tasks.json"),s={label:et,type:"shell",command:"vespercli worktree bootstrap --quiet",presentation:{reveal:"silent",panel:"shared"},problemMatcher:[],runOptions:{runOn:"folderOpen"}},r={version:"2.0.0",tasks:[]},o=!1;try{let a=await b(t,"utf-8");r=de(a),Array.isArray(r.tasks)||(r.tasks=[]),o=!0}catch(a){if(a.code!=="ENOENT")throw a}let i=r.tasks.findIndex(a=>a?.label===et);if(i===-1)r.tasks.push(s);else if(JSON.stringify(r.tasks[i])!==JSON.stringify(s))r.tasks[i]=s;else return{created:!1,updated:!1};return await le(q(t),{recursive:!0}),await A(t,JSON.stringify(r,null," "),"utf-8"),{created:!o,updated:o}}var tt=["react-scripts","**/node_modules/.bin/react-scripts","next","**/node_modules/.bin/next","vite","**/node_modules/.bin/vite","webpack","**/node_modules/.bin/webpack","turbo","**/node_modules/.bin/turbo","tsc","**/node_modules/.bin/tsc","tsup","**/node_modules/.bin/tsup","esbuild","**/node_modules/.bin/esbuild","rollup","**/node_modules/.bin/rollup","parcel","**/node_modules/.bin/parcel","jest","**/node_modules/.bin/jest","vitest","**/node_modules/.bin/vitest","npx vitest","pnpm vitest","pnpm vitest run","pnpm exec vitest","pnpm dlx vitest","mocha","**/node_modules/.bin/mocha","playwright","**/node_modules/.bin/playwright","npx playwright open","npx playwright test","npx playwright show-report","npx playwright codegen","open playwright","open playwright-report/index.html",'ps aux | grep "playwright test" | grep -v grep | wc -l',"cypress","**/node_modules/.bin/cypress","pytest","npx","pnpm dlx","pnpm exec","yarn dlx","npm test","npm run","npm start","npm run test","npm run build","npm run dev","npm run lint","pnpm test","pnpm run","pnpm start","pnpm tsc","yarn test","yarn run","yarn start","eslint","**/node_modules/.bin/eslint","pnpm eslint","prettier","**/node_modules/.bin/prettier","biome","**/node_modules/.bin/biome","stylelint","**/node_modules/.bin/stylelint","mkdir","touch","cat","ls","head","tail","wc","grep","find","tree","file","stat","realpath","basename","dirname","awk","sed","cut","sort","uniq","tr","xargs","column","paste","join","comm","diff","cmp","git status","git log","git diff","git branch","git show","git remote","git tag","git rev-parse","git describe","git ls-files","git ls-tree","git blame","git shortlog","pushd","popd","dirs","echo","pwd","which","type","env","printenv","date","hostname","whoami","uname","lsof","pkill","node --version","npm --version","pnpm --version","yarn --version","python --version","python3 --version","curl -I *","curl --head *","curl -sI *","curl -s http://localhost:*","curl -s http://127.0.0.1:*","curl -sf http://localhost:*","curl -sf http://127.0.0.1:*","curl --fail http://localhost:*","curl --fail http://127.0.0.1:*","tsx","**/node_modules/.bin/tsx","npx tsx","/^(\\w+=\\S+\\s+)+(npx|node|tsx|npm|pnpm|yarn)\\b/","vespercli","vespercli init","vespercli add","vespercli list","vespercli ls","vespercli reset","vespercli catalog","**/node_modules/.bin/vespercli","mcp: vesper-indexing: vesper_search","mcp: vesper-indexing: vesper_symbols","mcp: vesper-indexing: vesper_status","mcp: vesper-indexing: vesper_reindex","python3 << 'PYEOF'",'python3 << "PYEOF"',"python3 << 'EOF'",'python3 << "EOF"',"python3 << 'END'","python << 'PYEOF'",'python << "PYEOF"',"python << 'EOF'","cat << 'EOF'",'cat << "EOF"',"cat << 'END'","bash << 'EOF'","sh << 'EOF'","cat << 'RESEARCH_EOF'",'cat << "RESEARCH_EOF"',"RESEARCH_EOF","tee","node -e","python3 -c","python -c"],L=["vesper_search","vesper_symbols","vesper_status","vesper_reindex","resolve-library-id","get-library-docs","query-docs","sequentialthinking","create_entities","create_relations","add_observations","delete_entities","delete_observations","delete_relations","read_graph","search_nodes","open_nodes"],Re={"clickup-agent":["clickup_add_tag_to_task","clickup_add_time_entry","clickup_attach_task_file","clickup_create_document","clickup_create_document_page","clickup_create_folder","clickup_create_list","clickup_create_list_in_folder","clickup_create_task","clickup_create_task_comment","clickup_find_member_by_name","clickup_get_chat_channels","clickup_get_current_time_entry","clickup_get_document_pages","clickup_get_folder","clickup_get_list","clickup_get_task","clickup_get_task_comments","clickup_get_task_time_entries","clickup_get_workspace_hierarchy","clickup_get_workspace_members","clickup_list_document_pages","clickup_remove_tag_from_task","clickup_resolve_assignees","clickup_search","clickup_send_chat_message","clickup_start_time_tracking","clickup_stop_time_tracking","clickup_update_document_page","clickup_update_folder","clickup_update_list","clickup_update_task"]},V={"vesper-indexing":{description:"Fast code search with semantic indexing",config:{type:"stdio",command:"node",args:["${VESPER_INDEXING_PATH}"],env:{VESPER_INDEX_ROOT:"${workspaceFolder}"}},tools:["vesper_search","vesper_symbols","vesper_status","vesper_reindex"]},context7:{description:"Documentation lookup for libraries",config:{type:"stdio",command:"npx",args:["-y","@upstash/context7-mcp"]},tools:["resolve-library-id","get-library-docs","query-docs"]},"sequential-thinking":{description:"Step-by-step reasoning for complex problems",config:{type:"stdio",command:"npx",args:["-y","@modelcontextprotocol/server-sequential-thinking"]},tools:["sequentialthinking"]},clickup:{description:"ClickUp project management integration",config:{type:"stdio",command:"npx",args:["-y","@anthropics/mcp-clickup"],env:{CLICKUP_API_KEY:"${env:CLICKUP_API_KEY}",CLICKUP_TEAM_ID:"${env:CLICKUP_TEAM_ID}"}},tools:["clickup_add_tag_to_task","clickup_add_time_entry","clickup_attach_task_file","clickup_create_document","clickup_create_document_page","clickup_create_folder","clickup_create_list","clickup_create_list_in_folder","clickup_create_task","clickup_create_task_comment","clickup_find_member_by_name","clickup_get_chat_channels","clickup_get_current_time_entry","clickup_get_document_pages","clickup_get_folder","clickup_get_list","clickup_get_task","clickup_get_task_comments","clickup_get_task_time_entries","clickup_get_workspace_hierarchy","clickup_get_workspace_members","clickup_list_document_pages","clickup_remove_tag_from_task","clickup_resolve_assignees","clickup_search","clickup_send_chat_message","clickup_start_time_tracking","clickup_stop_time_tracking","clickup_update_document_page","clickup_update_folder","clickup_update_list","clickup_update_task"]},memory:{description:"Persistent knowledge graph memory for AI agents",config:{type:"stdio",command:"npx",args:["-y","@modelcontextprotocol/server-memory"],env:{MEMORY_FILE_PATH:"${workspaceFolder}/.vesper/memory.jsonl"}},tools:["create_entities","create_relations","add_observations","delete_entities","delete_observations","delete_relations","read_graph","search_nodes","open_nodes"]}};var E={FOLDER:"folder",WORKSPACE_FILE:"workspace"};async function Us(e){try{let s=(await js(e,{withFileTypes:!0})).find(r=>r.isFile()&&r.name.endsWith(".code-workspace"));return s?y(e,s.name):null}catch{return null}}async function _(e){let t=await Us(e);return t?{type:E.WORKSPACE_FILE,settingsPath:t,workspaceFile:t}:{type:E.FOLDER,settingsPath:y(e,".vscode","settings.json"),workspaceFile:null}}function je(e,t=null){return t?.workspaceFile?y(q(t.workspaceFile),".vesperrc"):y(e,".vesperrc")}function de(e){let t=Ls(e,{trailingCommas:!0});return JSON.parse(t)}async function x(e){let t=await _(e);try{let s=await b(t.settingsPath,"utf-8"),r=de(s);return t.type===E.WORKSPACE_FILE?r.settings||{}:r}catch(s){if(s.code==="ENOENT")return{};if(s instanceof SyntaxError){if(t.type===E.WORKSPACE_FILE)throw new Error(`Failed to parse workspace file: ${t.settingsPath}. ${s.message}`);return{}}throw s}}async function P(e,t){let s=await _(e);if(s.type===E.WORKSPACE_FILE){let r;try{let o=await b(s.settingsPath,"utf-8");r=de(o)}catch(o){if(o.code==="ENOENT")r={folders:[],settings:{}};else throw new Error(`Failed to read workspace file: ${s.settingsPath}. ${o.message}`)}r.settings=t,await A(s.settingsPath,JSON.stringify(r,null," "),"utf-8")}else{let r=q(s.settingsPath);await le(r,{recursive:!0}),await A(s.settingsPath,JSON.stringify(t,null," "),"utf-8")}}function Gs(e){return y(e,".vesper","tracking.json")}async function g(e){let t=await _(e),s=je(e,t),r=Gs(e),o=y(e,".vesperrc");try{let i=await b(s,"utf-8");return JSON.parse(i)}catch{if(s!==o)try{let i=await b(o,"utf-8");return JSON.parse(i)}catch{}try{let i=await b(r,"utf-8");return JSON.parse(i)}catch{return{paths:[],addedAt:null,workspaceType:null,settingsPath:null}}}}async function Ws(e){try{let t=await b(e,"utf-8"),r=de(t).folders||[],o=q(e);return r.map(i=>{let a=i.path||i;return a.startsWith("/")||a.startsWith("~")?a.replace(/^~/,it()):y(o,a)})}catch{return[]}}async function vt(e){let t=await _(e);if(t.type!==E.WORKSPACE_FILE)return{found:!1,paths:[]};let s=q(t.workspaceFile),r=y(s,".vesperrc"),o=await Ws(t.workspaceFile),i=[];for(let a of o){let c=y(a,".vesperrc");if(c!==r)try{let d=await b(c,"utf-8"),l=JSON.parse(d);i.push({folderPath:a,vesperrcPath:c,tracking:l})}catch{}}return{found:i.length>0,paths:i}}async function wt(e,t,s){let r=await _(e),o=je(e,r),i={...s,workspaceType:E.WORKSPACE_FILE,settingsPath:r.settingsPath,migratedFrom:t,migratedAt:new Date().toISOString()};await A(o,JSON.stringify(i,null,2),"utf-8");try{let{unlink:a}=await import("node:fs/promises");await a(t)}catch{}return{success:!0,newPath:o}}async function C(e,t){let s=await _(e),r=je(e,s);await A(r,JSON.stringify(t,null,2),"utf-8")}async function yt(e,t){let s=await _(e),r=await x(e),o=await g(e),i=[],a=[];for(let{path:c,settingKey:d}of t){if(r[d]||(r[d]={}),r[d][c]){a.push(c),o.paths.includes(c)||o.paths.push(c);continue}r[d][c]=!0,i.push(c),o.paths.includes(c)||o.paths.push(c)}return i.length>0&&await P(e,r),o.paths.length>0&&(o.addedAt=o.addedAt||new Date().toISOString(),o.updatedAt=new Date().toISOString(),o.workspaceType=s.type,o.settingsPath=s.settingsPath,await C(e,o)),{added:i,skipped:a,workspaceType:s.type}}async function _t(e){let t=await x(e),s=await g(e),r={paths:[],settings:[],mcpServers:[],agentTools:[]},o=/vespercli|vesper-cli/;for(let p of Object.values(te))if(t[p]){for(let u of Object.keys(t[p])){let f=s.paths?.includes(u),h=o.test(u);(f||h)&&(delete t[p][u],r.paths.includes(u)||r.paths.push(u))}Object.keys(t[p]).length===0&&delete t[p]}let i=s.readAccessPaths||[];if(i.length>0){let p=t[S]||[],u=p.filter(f=>!i.includes(f));u.length!==p.length&&(u.length>0?t[S]=u:delete t[S],r.settings.push(S))}for(let p of Ns)t[p]!==void 0&&(delete t[p],r.settings.push(p));let a=s.mcp?.agentTools||{};for(let[p,u]of Object.entries(a))r.agentTools.push({agent:p,tools:u});(r.paths.length>0||r.settings.length>0)&&await P(e,t);let c=await F(e),d=s.mcp?.servers||[],l=[...new Set([...K,...d])];if(c.servers){for(let p of l)c.servers[p]&&(delete c.servers[p],r.mcpServers.push(p));if(r.mcpServers.length>0){let p=_e(e),u=q(p);await le(u,{recursive:!0}),await A(p,JSON.stringify(c,null," "),"utf-8")}}return await C(e,{paths:[],readAccessPaths:[],addedAt:null,workspaceType:null,settingsPath:null,mcp:null}),{removed:r}}async function he(e){return(await g(e)).paths.length>0}async function D(e){let t=await g(e),s=[];return Array.isArray(t.paths)&&t.paths.length>0&&s.push("copilot"),t.claude&&s.push("claude"),s}var Bs=["agents","prompts","instructions"];function qs(){let e=[];for(let r of Bs){let o=I[r],i=te[r];if(i&&o){let a=B(y(T,"core",o.dir));e.push({path:a,settingKey:i,type:r})}}let t=te.skills;if(t){let r=B(y(T,"core","skills"));e.push({path:r,settingKey:t,type:"skills"})}let s=I.skills;if(t&&s){let r=B(y(T,s.dir));e.push({path:r,settingKey:t,type:"skills"})}return e}async function St(e,t=!0){let s=await _(e),r=await x(e);if(r[ct]=t,t){r[ce]||(r[ce]={});for(let o of tt)r[ce][o]=!0}return await P(e,r),{configured:t?tt.length:0,workspaceType:s.type}}async function xt(e,t={}){let{maxRequests:s=M.maxRequests,omitBaseAgentInstructions:r=M.omitBaseAgentInstructions}=t,o=await x(e);o[lt]=s,o[dt]=!0,o[ut]=!0,o[pt]=!0,o[ft]=r,o[gt]=!0,o[mt]="newAndOutdated",o[S]||(o[S]=[]),await P(e,o)}async function kt(e,t){let s=await x(e),r=s[S]||[];r.includes(t)||(r.push(t),s[S]=r,await P(e,s));let o=await g(e);return o.readAccessPaths||(o.readAccessPaths=[]),o.readAccessPaths.includes(t)||(o.readAccessPaths.push(t),o.updatedAt=new Date().toISOString(),await C(e,o)),r}async function Ct(e,t){let s=await x(e),r=s[S]||[],o=r.indexOf(t);o!==-1&&(r.splice(o,1),s[S]=r,await P(e,s));let i=await g(e);if(i.readAccessPaths){let a=i.readAccessPaths.indexOf(t);a!==-1&&(i.readAccessPaths.splice(a,1),i.updatedAt=new Date().toISOString(),await C(e,i))}return r}async function At(e){return(await x(e))[S]||[]}function Pt(e){let t=I[e];if(!t)throw new Error(`Unknown asset type: ${e}`);let s=te[e];return{path:B(y(T,t.dir)),settingKey:s,type:e}}function H(e,t){if(Ie(t),!I[e])throw new Error(`Unknown asset type: ${e}`);let r=te[e];return{path:B(Xe(e,t)),settingKey:r,type:e,name:t}}async function se(e){return(await g(e)).paths}async function Et(e){let t={assetPaths:0,readAccess:0,commandKeys:0,trackingPaths:0,mcpArgs:0},s=(u,f)=>{let h=[];for(let O of u){let ae=fe(O);ae!==O&&t[f]++,h.includes(ae)||h.push(ae)}return h},r=await x(e),o=!1;for(let u of Object.values(te)){let f=r[u];if(!(!f||typeof f!="object"))for(let h of Object.keys(f)){let O=fe(h);if(O===h)continue;let ae=f[h];delete f[h],f[O]=f[O]===!0?!0:ae,t.assetPaths++,o=!0}}if(Array.isArray(r[S])){let u=t.readAccess;r[S]=s(r[S],"readAccess"),t.readAccess!==u&&(o=!0)}let i=r[ce];if(i&&typeof i=="object")for(let u of Object.keys(i))Fs(u)&&(delete i[u],t.commandKeys++,o=!0);o&&await P(e,r);let a=await g(e),c=!1;if(Array.isArray(a.paths)){let u=t.trackingPaths;a.paths=s(a.paths,"trackingPaths"),t.trackingPaths!==u&&(c=!0)}if(Array.isArray(a.readAccessPaths)){let u=[];for(let f of a.readAccessPaths){let h=fe(f);h!==f&&(c=!0),u.includes(h)||u.push(h)}a.readAccessPaths=u}c&&(a.updatedAt=new Date().toISOString(),await C(e,a));let d=await F(e),l=d.servers?.["vesper-indexing"];if(l&&Array.isArray(l.args)){let u=!1;l.args=l.args.map(f=>{let h=fe(f);return h!==f&&(t.mcpArgs++,u=!0),h}),u&&await Se(e,d)}return{migrated:t.assetPaths+t.readAccess+t.commandKeys+t.trackingPaths+t.mcpArgs>0,changed:t}}async function Tt(e){let t=await _(e),s=await x(e),r=await g(e),o=qs(),i=[],a=[];for(let{path:l,settingKey:p}of o)s[p]||(s[p]={}),s[p][l]===!0?a.push(l):(s[p][l]=!0,i.push(l)),r.paths.includes(l)||r.paths.push(l);let c=T,d=s[S]||[];return d.includes(c)||(d.push(c),s[S]=d,i.push(c)),r.readAccessPaths||(r.readAccessPaths=[]),r.readAccessPaths.includes(c)||r.readAccessPaths.push(c),i.length>0&&await P(e,s),r.addedAt=r.addedAt||new Date().toISOString(),r.updatedAt=new Date().toISOString(),r.workspaceType=t.type,r.settingsPath=t.settingsPath,await C(e,r),{added:i,existed:a,workspaceType:t.type}}var st="# <!-- vesper:hook:start -->",rt="# <!-- vesper:hook:end -->";async function Ks(e){let{execFile:t}=await import("node:child_process"),{promisify:s}=await import("node:util"),r=s(t),o=async p=>{try{let{stdout:u}=await r("git",p,{cwd:e});return u.trim()}catch{return null}};if(await o(["rev-parse","--is-inside-work-tree"])!=="true")return null;let{isAbsolute:a}=await import("node:path"),c=p=>a(p)?p:y(e,p),d=await o(["config","core.hooksPath"]);if(d)return c(d);let l=await o(["rev-parse","--git-common-dir"]);return l?y(c(l),"hooks"):null}async function Hs(e,t){let s=await Ks(e);if(!s)return{installed:!1,updated:!1,hooksDir:null};let r=y(T,"hooks",t),o=await b(r,"utf-8"),i=o.match(new RegExp(`${st}[\\s\\S]*?${rt}`));if(!i)throw new Error(`Hook source ${r} is missing its vesper:hook guard markers`);let a=i[0],c=new RegExp(`${st}[\\s\\S]*?${rt}`);await le(s,{recursive:!0});let d=y(s,t),l="",p=!0;try{l=await b(d,"utf-8")}catch(f){if(f.code!=="ENOENT")throw f;p=!1}if(!p)return await A(d,o,{encoding:"utf-8",mode:493}),{installed:!0,updated:!1,hooksDir:s};if(c.test(l)){let f=l.replace(c,a);return f!==l?(await A(d,f,"utf-8"),await nt(d),{installed:!1,updated:!0,hooksDir:s}):{installed:!1,updated:!1,hooksDir:s}}let u=l.endsWith(`
9
+ `)?`
10
+ `:`
11
+
12
+ `;return await A(d,`${l}${u}${a}
13
+ `,"utf-8"),await nt(d),{installed:!1,updated:!0,hooksDir:s}}async function nt(e){let{chmod:t}=await import("node:fs/promises");try{await t(e,493)}catch{}}var Js=["pre-commit","post-checkout"];async function ve(e){let t={};for(let s of Js)t[s]=await Hs(e,s);return t}var ot="# <!-- vesper:gitattributes:start -->",at="# <!-- vesper:gitattributes:end -->",zs=[".vesper/history.md merge=union",".vesper/memory.jsonl merge=vesper-memory"];async function we(e){let t=y(e,".gitattributes"),s=[ot,...zs,at].join(`
14
+ `),r=new RegExp(`${ot}[\\s\\S]*?${at}`),o="";try{o=await b(t,"utf-8")}catch(a){if(a.code!=="ENOENT")throw a;return await A(t,`${s}
15
+ `,"utf-8"),{created:!0,updated:!1}}if(r.test(o)){let a=o.replace(r,s);return a!==o?(await A(t,a,"utf-8"),{created:!1,updated:!0}):{created:!1,updated:!1}}let i=o.endsWith(`
16
+ `)?`
17
+ `:`
18
+
19
+ `;return await A(t,`${o}${i}${s}
20
+ `,"utf-8"),{created:!1,updated:!0}}async function ye(e){let{execFile:t}=await import("node:child_process"),{promisify:s}=await import("node:util"),r=s(t),o=async l=>{try{return await r("git",l,{cwd:e}),!0}catch{return!1}};if(!await o(["rev-parse","--is-inside-work-tree"]))return{configured:!1};let c=`node "${y(T,"hooks","merge-memory-jsonl.js")}" %O %A %B`;return await o(["config","merge.vesper-memory.name","Vesper memory.jsonl entity-aware merge"]),{configured:await o(["config","merge.vesper-memory.driver",c])}}function _e(e){return y(e,".vscode","mcp.json")}function W(){return y(Z,"src","mcp","vesper-indexing","dist","index.js")}async function F(e){let t=_e(e);try{let s=await b(t,"utf-8");return de(s)}catch(s){if(s.code==="ENOENT")return{servers:{}};if(s instanceof SyntaxError)return{servers:{}};throw s}}async function Se(e,t){let s=_e(e),r=q(s);await le(r,{recursive:!0}),await A(s,JSON.stringify(t,null," "),"utf-8")}async function J(e,t=!0){let s=await F(e),r=B(W()),o=[];if(s.servers||(s.servers={}),t?(s.servers["vesper-indexing"]={type:"stdio",command:"node",args:[r],env:{VESPER_INDEX_ROOT:"${workspaceFolder}"}},o.push("vesper-indexing"),s.servers["sequential-thinking"]={type:"stdio",command:"npx",args:["-y","@modelcontextprotocol/server-sequential-thinking"]},o.push("sequential-thinking"),s.servers.memory={type:"stdio",command:"npx",args:["-y","@modelcontextprotocol/server-memory"],env:{MEMORY_FILE_PATH:"${workspaceFolder}/.vesper/memory.jsonl"}},o.push("memory")):(delete s.servers["vesper-indexing"],delete s.servers["sequential-thinking"],delete s.servers.memory),await Se(e,s),t&&o.length>0){let i=await g(e);i.mcp=i.mcp||{},i.mcp.servers=o,i.mcp.updatedAt=new Date().toISOString(),await C(e,i)}return{configured:t,mcpPath:_e(e),servers:o}}async function xe(e){return!!(await F(e)).servers?.["vesper-indexing"]}async function bt(e){let t=await _(e),s=await x(e);s[De]=!1,s[v]||(s[v]={});for(let r of L)s[v][r]=!0;return await P(e,s),{configured:L.length,workspaceType:t.type}}async function $t(e,t){let s=Re[t];if(!s||s.length===0)return{added:[],agentName:t};let r=await x(e),o=await _(e),i=await g(e,o);r[v]||(r[v]={});let a=[];for(let c of s)r[v][c]||(r[v][c]=!0,a.push(c));return a.length>0&&(await P(e,r),i.mcp=i.mcp||{},i.mcp.agentTools=i.mcp.agentTools||{},i.mcp.agentTools[t]=s,i.mcp.updatedAt=new Date().toISOString(),await C(e,i)),{added:a,agentName:t}}async function Ot(e,t){let s=V[t];if(!s)return{added:!1,serverName:t,tools:[],error:`Unknown MCP server: ${t}`};let r=await F(e),o=await x(e),i=await _(e),a=await g(e,i);if(r.servers||(r.servers={}),r.servers[t])return{added:!1,serverName:t,tools:[],error:"Already configured"};let c=JSON.parse(JSON.stringify(s.config));if(t==="vesper-indexing"){let l=B(W());c.args&&(c.args=c.args.map(p=>p==="${VESPER_INDEXING_PATH}"?l:p))}r.servers[t]=c,await Se(e,r),o[v]||(o[v]={});let d=[];for(let l of s.tools||[])o[v][l]||(o[v][l]=!0,d.push(l));return o[De]=!1,await P(e,o),a.mcp=a.mcp||{},a.mcp.servers=a.mcp.servers||[],a.mcp.servers.includes(t)||a.mcp.servers.push(t),a.mcp.updatedAt=new Date().toISOString(),await C(e,a),{added:!0,serverName:t,tools:d}}async function It(e,t){let s=V[t],r=await F(e),o=await x(e),i=await _(e),a=await g(e,i),c=!1;r.servers&&r.servers[t]&&(delete r.servers[t],await Se(e,r),c=!0);let d=[];if(s&&o[v]){for(let l of s.tools||[])o[v][l]&&(delete o[v][l],d.push(l));d.length>0&&await P(e,o)}return a.mcp?.servers&&(a.mcp.servers=a.mcp.servers.filter(l=>l!==t),a.mcp.updatedAt=new Date().toISOString(),await C(e,a)),{removed:c,serverName:t,tools:d}}import{readFile as N,writeFile as $,mkdir as z,readdir as Dt,rm as Mt,cp as Rt}from"node:fs/promises";import{join as w,dirname as Ve,basename as Ys}from"node:path";import{homedir as Xs}from"node:os";G();var re=w(T,"claude"),jt=["agents","commands","skills"],ke="vesper";function Y(e=ke){return w(Xs(),".claude","skills",e)}function Ce(e){return w(e,".claude","vesper")}function Lt(e){return w(e,"CLAUDE.md")}function X(e){return w(e,".mcp.json")}function Ae(e){return w(e,".claude","settings.json")}function Vt(e,t){return t?e.replace(/^(name:\s*)([a-z0-9-]+)/m,(s,r,o)=>o.startsWith(t)?s:`${r}${t}${o}`):e}async function Qs(e,t,s,r){if(!await m(e))return{copied:0};await z(t,{recursive:!0});let o=await Dt(e,{withFileTypes:!0}),i=0;for(let a of o){let c=w(e,a.name);if(a.isDirectory()){await Rt(c,w(t,a.name),{recursive:!0}),i+=1;continue}if(!a.name.endsWith(".md"))continue;let d=await N(c,"utf-8"),l=Vt(d,s),p=r&&s&&!a.name.startsWith(s)?`${s}${a.name}`:a.name;await $(w(t,p),l,"utf-8"),i+=1}return{copied:i}}async function Zs(e,t,s){let r=w(e,".claude-plugin");await z(r,{recursive:!0});let o={name:t,description:"Vesper specialist catalog \u2014 subagents, slash commands, and skills for AI-orchestrated development.",version:s};await $(w(r,"plugin.json"),JSON.stringify(o,null,2),"utf-8")}async function Pe({pluginName:e=ke,namePrefix:t="",version:s="0.0.0"}={}){let r=Y(e),o={};for(let i of jt){let a=w(re,i),c=w(r,i),l=await Qs(a,c,i==="skills"?"":t,i!=="skills");o[i]=l.copied}return await Zs(r,e,s),{pluginDir:r,counts:o}}async function Ft(e,t,{pluginName:s=ke,namePrefix:r=""}={}){let o=Y(s),i=w(o,e);if(await z(i,{recursive:!0}),e==="skills"){let u=w(re,"skills",t);if(!await m(u))throw new Error(`Skill "${t}" not found in assets/claude/skills/`);return await Rt(u,w(i,t),{recursive:!0}),{installedAs:t}}let a=".md",c=w(re,e,`${t}${a}`);if(!await m(c))throw new Error(`${e.slice(0,-1)} "${t}" not found in assets/claude/${e}/`);let d=await N(c,"utf-8"),l=Vt(d,r),p=r&&!t.startsWith(r)?`${r}${t}${a}`:`${t}${a}`;return await $(w(i,p),l,"utf-8"),{installedAs:Ys(p,a)}}async function Nt(e=ke){let t=Y(e),s={};for(let r of jt){let o=w(t,r);if(!await m(o)){s[r]=[];continue}let i=await Dt(o,{withFileTypes:!0});s[r]=r==="skills"?i.filter(a=>a.isDirectory()).map(a=>a.name).sort():i.filter(a=>a.isFile()&&a.name.endsWith(".md")).map(a=>a.name.replace(/\.md$/,"")).sort()}return s}var Fe="<!-- vesper:start -->",Ne="<!-- vesper:end -->";function er(){return[Fe,"@.claude/vesper/orchestrator.md","@.claude/vesper/orchestration.md","@.claude/vesper/context.md",Ne].join(`
21
+ `)}async function tr(e){let t=Lt(e),s=er(),r=new RegExp(`${Fe}[\\s\\S]*?${Ne}`);if(!await m(t))return await z(Ve(t),{recursive:!0}),await $(t,`${s}
22
+ `,"utf-8"),{created:!0,updated:!1};let o=await N(t,"utf-8");if(r.test(o)){let a=o.replace(r,s);return a!==o?(await $(t,a,"utf-8"),{created:!1,updated:!0}):{created:!1,updated:!1}}let i=`${s}
23
+
24
+ ${o}`;return await $(t,i,"utf-8"),{created:!1,updated:!0}}function sr(e){let t=new RegExp(`${Fe}[\\s\\S]*?${Ne}\\n*`);return e.replace(t,"")}async function Ee(e){let t=Ce(e);await z(t,{recursive:!0});let s={orchestrator:"refreshed",orchestration:"skipped",context:"skipped"},r=w(re,"vesper-orchestrator.md"),o=w(t,"orchestrator.md");await $(o,await N(r,"utf-8"),"utf-8");let i=w(t,"orchestration.md");await m(i)||(await $(i,await N(w(re,"orchestration.md.tpl"),"utf-8"),"utf-8"),s.orchestration="created");let a=w(t,"context.md");await m(a)||(await $(a,await N(w(re,"context.md.tpl"),"utf-8"),"utf-8"),s.context="created");let c=await tr(e);return s.claudeMd=c.created?"created":c.updated?"updated":"unchanged",s}async function ue(e){let t=X(e);try{let s=await N(t,"utf-8");return JSON.parse(s)}catch(s){return s.code==="ENOENT"?{mcpServers:{}}:{mcpServers:{}}}}async function Ue(e,t){let s=X(e);await z(Ve(s),{recursive:!0}),await $(s,JSON.stringify(t,null," "),"utf-8")}function rr(e){return{"vesper-indexing":{command:"node",args:[W()],env:{VESPER_INDEX_ROOT:e}},"sequential-thinking":{command:"npx",args:["-y","@modelcontextprotocol/server-sequential-thinking"]},memory:{command:"npx",args:["-y","@modelcontextprotocol/server-memory"],env:{MEMORY_FILE_PATH:w(e,".vesper","memory.jsonl")}}}}async function Q(e,t=!0){let s=await ue(e);s.mcpServers||(s.mcpServers={});let r=rr(e),o=Object.keys(r);if(t)for(let[i,a]of Object.entries(r))s.mcpServers[i]=a;else for(let i of o)delete s.mcpServers[i];return await Ue(e,s),{configured:t,mcpPath:X(e),servers:t?o:[]}}function Le(e,t){return String(e).replace(/\$\{VESPER_INDEXING_PATH\}/g,W()).replace(/\$\{workspaceFolder\}/g,t).replace(/\$\{env:([^}]+)\}/g,"$${$1}")}function nr(e,{workspaceRoot:t}){let{type:s,...r}=structuredClone(e);if(typeof r.command=="string"&&(r.command=Le(r.command,t)),Array.isArray(r.args)&&(r.args=r.args.map(o=>Le(o,t))),r.env&&typeof r.env=="object")for(let[o,i]of Object.entries(r.env))r.env[o]=Le(i,t);return r}async function Ut(e,t){if(K.includes(t))return{added:!1,serverName:t,error:`${t} is a Vesper-managed core server \u2014 use "vespercli mcp enable --target claude" instead.`};let s=V[t];if(!s)return{added:!1,serverName:t,error:`Unknown MCP server: ${t}`};let r=await ue(e);if(r.mcpServers||(r.mcpServers={}),r.mcpServers[t])return{added:!1,serverName:t,error:"Already configured"};r.mcpServers[t]=nr(s.config,{workspaceRoot:e}),await Ue(e,r);let o=await g(e);return o.mcp=o.mcp||{},o.mcp.servers=o.mcp.servers||[],o.mcp.servers.includes(t)||o.mcp.servers.push(t),o.mcp.updatedAt=new Date().toISOString(),await C(e,o),{added:!0,serverName:t}}async function Gt(e,t){if(K.includes(t))return{removed:!1,serverName:t,error:`${t} is a Vesper-managed core server \u2014 use "vespercli mcp disable --target claude" instead.`};let s=await ue(e),r=!1;s.mcpServers&&s.mcpServers[t]&&(delete s.mcpServers[t],await Ue(e,s),r=!0);let o=await g(e);return o.mcp?.servers&&(o.mcp.servers=o.mcp.servers.filter(i=>i!==t),o.mcp.updatedAt=new Date().toISOString(),await C(e,o)),{removed:r,serverName:t}}async function Wt(e){let t=await ue(e),s=Object.keys(t.mcpServers||{}),r=s.filter(o=>!V[o]);return{configured:s,custom:r}}async function Bt(e){let t=new Set,s=[];try{s=await D(e)}catch{s=[]}if(s.includes("claude"))try{let a=await ue(e);for(let c of Object.keys(a.mcpServers||{}))t.add(c)}catch{}if(s.includes("copilot"))try{let a=await F(e);for(let c of Object.keys(a.servers||{}))t.add(c)}catch{}let r=[];try{let a=await g(e);r=Array.isArray(a.mcp?.servers)?a.mcp.servers:[]}catch{r=[]}let o=new Set(r);return{drifted:[...t].filter(a=>!K.includes(a)&&!o.has(a))}}async function Te(e){let t=Ae(e),s={};try{s=JSON.parse(await N(t,"utf-8"))}catch{s={}}s.permissions||(s.permissions={}),Array.isArray(s.permissions.allow)||(s.permissions.allow=[]);let r=["mcp__vesper-indexing__vesper_search","mcp__vesper-indexing__vesper_symbols","mcp__vesper-indexing__vesper_status","mcp__vesper-indexing__vesper_reindex","mcp__sequential-thinking__sequentialthinking","mcp__memory__create_entities","mcp__memory__create_relations","mcp__memory__add_observations","mcp__memory__delete_entities","mcp__memory__delete_observations","mcp__memory__delete_relations","mcp__memory__read_graph","mcp__memory__search_nodes","mcp__memory__open_nodes"],o=0;for(let i of r)s.permissions.allow.includes(i)||(s.permissions.allow.push(i),o+=1);return ir(s),await z(Ve(t),{recursive:!0}),await $(t,JSON.stringify(s,null," "),"utf-8"),{configured:o,settingsPath:t}}var qt=".claude/vesper/",or=`node -e "['orchestrator','orchestration','context'].forEach(n=>{try{process.stdout.write(require('fs').readFileSync('.claude/vesper/'+n+'.md','utf8')+'\\n\\n')}catch(e){}})"`,Kt="worktree bootstrap",ar="command -v vespercli >/dev/null 2>&1 && vespercli worktree bootstrap --quiet || true";function ir(e){e.hooks||(e.hooks={}),Array.isArray(e.hooks.SessionStart)||(e.hooks.SessionStart=[]);let t=s=>e.hooks.SessionStart.some(r=>(r?.hooks||[]).some(o=>typeof o?.command=="string"&&o.command.includes(s)));t(qt)||e.hooks.SessionStart.push({matcher:"clear",hooks:[{type:"command",command:or}]}),t(Kt)||e.hooks.SessionStart.push({hooks:[{type:"command",command:ar}]})}function cr(e){Array.isArray(e?.hooks?.SessionStart)&&(e.hooks.SessionStart=e.hooks.SessionStart.filter(t=>!(t?.hooks||[]).some(s=>typeof s?.command=="string"&&(s.command.includes(qt)||s.command.includes(Kt)))),e.hooks.SessionStart.length===0&&delete e.hooks.SessionStart,e.hooks&&Object.keys(e.hooks).length===0&&delete e.hooks)}async function Ht(e,t){let s=await g(e);return s.claude={...s.claude,...t,updatedAt:new Date().toISOString()},await C(e,s),s.claude}async function be(e){let t=Ce(e);await Mt(t,{recursive:!0,force:!0});let s=Lt(e);if(await m(s)){let i=await N(s,"utf-8"),a=sr(i);a.trim()?await $(s,a,"utf-8"):await Mt(s,{force:!0})}await Q(e,!1);let r=Ae(e);if(await m(r))try{let i=JSON.parse(await N(r,"utf-8"));cr(i),await $(r,JSON.stringify(i,null," "),"utf-8")}catch{}let o=await g(e);delete o.claude,await C(e,o)}G();import{resolve as Ge,basename as _r}from"node:path";import{rm as Sr}from"node:fs/promises";import{confirm as Jt}from"@inquirer/prompts";import k from"picocolors";function lr(e){console.log(`${k.green("\u2713")} ${e}`)}function dr(e){console.log(`${k.red("\u2717")} ${e}`)}function ur(e){console.log(`${k.yellow("!")} ${e}`)}function pr(e){console.log(`${k.cyan("\u2192")} ${e}`)}function fr(e){console.log(k.dim(e))}function gr(e){return k.cyan(e)}function mr(e){return k.bold(e)}function hr(e){console.log(),console.log(k.bold(k.underline(e)))}function vr(e,t=!1){let s=t?k.green("\u25CF"):k.dim("\u25CB");console.log(` ${s} ${e}`)}function wr(){console.log(),console.log(k.bold(k.magenta("\u{1F3AF} Ready to use Vesper!"))),console.log(k.cyan(' In VS Code Chat, select "Vesper" from the agent dropdown')),console.log(k.cyan(" and start requesting!")),console.log()}function yr(e){let t=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],s=0,r=null,o=e,i=()=>{let a=k.cyan(t[s]);process.stdout.write(`\r${a} ${o}`),s=(s+1)%t.length};return{start(){process.stdout.write(`
25
+ `),r=setInterval(i,80),i()},update(a){o=a},stop(){r&&(clearInterval(r),r=null,process.stdout.write("\r"+" ".repeat(o.length+4)+"\r"))},succeed(a){this.stop(),console.log(`${k.green("\u2713")} ${a||o}`)},fail(a){this.stop(),console.log(`${k.red("\u2717")} ${a||o}`)}}}var n={success:lr,error:dr,warn:ur,info:pr,dim:fr,formatPath:gr,formatName:mr,header:hr,listItem:vr,vesperTip:wr,createSpinner:yr};async function xr(e={}){let t=Ge(e.path||process.cwd());if(!(await g(t)).claude){n.warn("Claude Code target is not initialized in this workspace.");return}if(!e.yes&&!await Jt({message:"Remove the Claude Code target from this project? (the shared plugin catalog at the user level is left untouched)",default:!1})){n.info("Reset cancelled.");return}await be(t),console.log(),n.success("Claude Code target reset complete."),n.info("Removed: .claude/vesper/, CLAUDE.md guard block, .mcp.json entry, .vesperrc.claude"),n.info("Left untouched: the shared plugin catalog at ~/.claude/skills/vesper/")}function kr(e){let t=new Set;for(let s of e)s.includes("/agents")&&t.add("Agents"),s.includes("/instructions")&&t.add("Instructions"),s.includes("/prompts")&&t.add("Prompts"),s.includes("/skills")&&t.add("Skills");return Array.from(t)}async function We(e){let t=await g(e);await _t(e);try{let r=await x(e);if(r[v]){let o=new Set(L),i=!1;for(let a of Object.keys(r[v]))o.has(a)||(delete r[v][a],i=!0);i&&await P(e,r)}}catch{}let s=Ge(e,".vesperrc");try{if(t.claude){let{writeFile:r}=await import("node:fs/promises");await r(s,JSON.stringify({paths:[],addedAt:null,workspaceType:null,settingsPath:null,claude:t.claude},null,2),"utf-8")}else await Sr(s,{force:!0})}catch{}}async function zt(e={}){try{let t=Ge(e.path||process.cwd());await m(t)||(n.error(`Directory not found: ${n.formatPath(t)}`),process.exit(1));let s=e.target;if(!s){let c=await D(t);if(c.length===0){n.warn("Vesper is not initialized in this workspace.");return}c.length>1&&(n.error("Both Copilot and Claude targets are installed here \u2014 specify which to reset: --target copilot|claude"),process.exit(1)),s=c[0]}if(s==="claude")return await xr({...e,path:t});if(!await he(t)){n.warn("Vesper is not initialized in this workspace.");return}let r=await se(t);if(r.length===0){n.info("Nothing to reset.");return}let o=kr(r);if(!e.yes&&!await Jt({message:`Remove all Vesper assets (${o.join(", ")})?`,default:!1})){n.info("Reset cancelled.");return}let i=await g(t),a=await _(t);await We(t),i.claude&&n.info("Claude Code target detected \u2014 kept its record in .vesperrc"),console.log(),n.success("Vesper reset complete."),i.workspaceType===E.WORKSPACE_FILE||a.type===E.WORKSPACE_FILE?n.info(`Cleaned: ${_r(a.settingsPath)}`):n.info("Cleaned: .vscode/settings.json"),n.info("Reload VS Code to apply changes")}catch(t){if(t.name==="ExitPromptError"){console.log(),n.info("Reset cancelled.");return}n.error(`Reset failed: ${t.message}`),process.exit(1)}}var Yt=["copilot","claude"];function Xt(e){return e==="claude"?"Claude Code":"GitHub Copilot"}async function Or(e){let t=await g(e),s=[];return Array.isArray(t.paths)&&t.paths.length>0&&s.push("copilot"),t.claude&&s.push("claude"),s}async function Ir(e,t){let s=await Or(t);if(e.target){let o=String(e.target).toLowerCase(),i=o==="all"?[...Yt]:o.split(",").map(a=>a.trim()).filter(Boolean);for(let a of i)Yt.includes(a)||(n.error(`Unknown target: ${a}. Valid targets: copilot, claude, all`),process.exit(1));return{selected:[...new Set(i)],installed:s}}return process.stdin.isTTY||(n.error("Non-interactive run without --target. Specify the platform(s), e.g. --target copilot,claude (or --target all)."),process.exit(1)),{selected:await $r({message:s.length?"Platforms to set up (checked = installed; uncheck to remove):":"Which AI platform(s) is this workspace for?",choices:[{name:"GitHub Copilot (VS Code)",value:"copilot",checked:s.includes("copilot")},{name:"Claude Code (CLI / VS Code extension / JetBrains / desktop)",value:"claude",checked:s.includes("claude")}]}),installed:s}}async function Mr(e){return e?"":await br({message:"Name Vesper's Claude Code subagents/skills/commands:",choices:[{name:"Plain names (recommended \u2014 matches the Copilot catalog 1:1)",value:""},{name:'Prefix with "vesper-" (avoids collisions with other Claude Code kits)',value:"vesper-"}],default:""})}async function Dr(e,t={}){let s=t.yes||t.forceDefault,r=await Mr(s);console.log(),n.header("Installing Vesper for Claude Code"),console.log();let{pluginDir:o,counts:i}=await Pe({namePrefix:r,version:t.version||"0.0.0"});n.success(`Specialist catalog installed: ${o}`),n.info(` agents: ${i.agents}, commands: ${i.commands}, skills: ${i.skills}`);let a=await Ee(e);n.success("Project files ready:"),n.info(` .claude/vesper/orchestrator.md (${a.orchestrator})`),n.info(` .claude/vesper/orchestration.md (${a.orchestration})`),n.info(` .claude/vesper/context.md (${a.context})`),n.info(` CLAUDE.md (${a.claudeMd})`);let c=await Q(e,!0);await Te(e),n.success(`MCP servers configured: .mcp.json (${c.servers.join(", ")})`),await Ht(e,{pluginPath:Y(),namePrefix:r,mcpConfigPath:X(e),settingsPath:Ae(e),installedAt:new Date().toISOString()})}async function Rr(e,t,s){console.log(),n.header("Configuring GitHub Copilot"),console.log();let r=await Tt(e);await xt(e,{maxRequests:s.maxRequests,omitBaseAgentInstructions:s.omitBaseAgentInstructions});let o=await St(e,s.terminalEnableAutoApprove),i=!1;return s.enableMcpServer&&(i=(await J(e,!0)).configured,await bt(e)),await ht(e),n.success("Core assets ensured: agents, prompts, instructions, skills"),n.info(`Max agent requests: ${s.maxRequests}`),o.configured>0?n.info(`Terminal auto-approval: ${o.configured} safe commands configured`):s.terminalEnableAutoApprove===!1&&n.info("Terminal auto-approval: disabled"),i&&(n.info("MCP servers: vesper-indexing, sequential-thinking, memory (.vscode/mcp.json)"),n.info("MCP tools auto-approval: vesper-indexing + context7 + sequential-thinking + memory")),r.workspaceType===E.WORKSPACE_FILE?n.info(`Settings added to: ${Ar(t.settingsPath)}`):n.info("Settings added to: .vscode/settings.json"),n.info("Tracking file: .vesperrc"),n.info("Worktree bootstrap task: .vscode/tasks.json (runs on folder open)"),{mcpConfigured:i}}async function jr(e,t){let s=await vt(e);if(!s.found)return{migrated:!1,from:null};let{paths:r}=s;console.log(),n.warn(`Found .vesperrc in nested folder${r.length>1?"s":""}:`);for(let{folderPath:a}of r)n.info(` \u2192 ${a}`);console.log();let o=r[0],i=!0;if(t||(i=await ne({message:"Migrate .vesperrc to workspace level? (recommended for multi-root workspaces)",default:!0})),i){let a=await wt(e,o.vesperrcPath,o.tracking);if(a.success){if(n.success("Migrated .vesperrc to workspace level"),n.info(` From: ${o.vesperrcPath}`),n.info(` To: ${a.newPath}`),r.length>1){let{unlink:c}=await import("node:fs/promises");for(let d=1;d<r.length;d++)try{await c(r[d].vesperrcPath),n.info(` Removed: ${r[d].vesperrcPath}`)}catch{}}return console.log(),{migrated:!0,from:o.folderPath}}}else n.info("Migration skipped. .vesperrc will remain in nested folder."),console.log();return{migrated:!1,from:null}}async function Lr(e){let{migrated:t,changed:s}=await Et(e);if(!t)return;let r=(i,a)=>`${i} ${a}${i>1?"s":""}`,o=[];s.assetPaths&&o.push(r(s.assetPaths,"asset path")),s.readAccess&&o.push(r(s.readAccess,"read-access path")),s.commandKeys&&o.push(r(s.commandKeys,"stale command")),s.trackingPaths&&o.push(r(s.trackingPaths,"tracked path")),s.mcpArgs&&o.push("MCP server path"),console.log(),n.info("Detected a workspace set up under the older `vesper-cli` package \u2014 migrating install paths."),n.success(`Migrated: ${o.join(", ")}`),console.log()}async function Vr(e,t){let s=e;return t||(s=await Er({message:"Workspace root directory:",default:s})),Cr(s)}async function Fr(e,t,s){let r=[];for(let o of t){let i=Xt(o),a=s;if(s||(a=await ne({message:`${i} is installed but was unchecked. Remove it from this project?`,default:!1})),!a){n.info(`Kept ${i}.`);continue}o==="claude"?await be(e):await We(e),r.push(o),n.success(`Removed ${i} from this project.`)}return r}async function Nr(e){if(e)return{maxRequests:M.maxRequests,terminalEnableAutoApprove:M.terminalEnableAutoApprove,omitBaseAgentInstructions:M.omitBaseAgentInstructions,enableMcpServer:M.enableMcpServer};console.log(),n.info("Configure VS Code Chat settings:");let t=await Tr({message:"Max agent requests per session (chat.agent.maxRequests):",default:M.maxRequests,min:1,max:1e3}),s=await ne({message:"Controls whether terminal commands are automatically approved. Enable terminal auto-approval? (chat.tools.terminal.enableAutoApprove)",default:M.terminalEnableAutoApprove});s&&n.info("Terminal auto-approval enabled with safe command whitelist");let r=await ne({message:"Omit base agent instructions for custom agents? (github.copilot.chat.omitBaseAgentInstructions)",default:M.omitBaseAgentInstructions}),o=await ne({message:"Enable vesper-indexing MCP server for fast code search?",default:M.enableMcpServer});return{maxRequests:t||M.maxRequests,terminalEnableAutoApprove:s,omitBaseAgentInstructions:r,enableMcpServer:o}}async function Be(e,t=!1){let s=W().replace("index.js","cli-index.js");if(!await m(s))return{success:!1,error:"MCP server not built"};t&&(console.log(),n.info("Starting workspace indexing..."));let r=t?null:n.createSpinner("Indexing workspace...");return r&&r.start(),new Promise(o=>{let i=Pr("node",[s,e],{stdio:["ignore","pipe","pipe"],env:{...process.env}}),a="",c=0;i.stderr.on("data",d=>{let l=d.toString().trim(),p=l.match(/Indexed (\d+) files/);if(p&&(c=parseInt(p[1],10),r&&r.update(`Indexing workspace... ${c} files`)),t&&l)for(let u of l.split(`
26
+ `))u.trim()&&n.info(u.replace("[vesper-indexing] ",""))}),i.stdout.on("data",d=>{a+=d.toString()}),i.on("close",d=>{try{let l=JSON.parse(a.trim());l.success?r?r.succeed(`Workspace indexed: ${l.filesIndexed} files`):n.success(`Workspace indexed: ${l.filesIndexed} files`):r?r.fail(`Indexing failed: ${l.error}`):n.error(`Indexing failed: ${l.error}`),o(l)}catch{d===0?(r?r.succeed(`Workspace indexed: ${c} files`):n.success(`Workspace indexed: ${c} files`),o({success:!0,filesIndexed:c})):(r?r.fail("Indexing failed"):n.error("Indexing failed"),o({success:!1,error:"Unknown error"}))}}),i.on("error",d=>{r?r.fail(`Indexing failed: ${d.message}`):n.error(`Indexing failed: ${d.message}`),o({success:!1,error:d.message})})})}function Ur({copilot:e,claude:t,indexingResult:s}){console.log(),n.success("Vesper is ready."),s?.success?n.info(`Code index built: ${s.filesIndexed} files.`):s?.error&&n.info("Code index will be built on first MCP server start."),console.log(),n.header("Next Steps"),console.log(),e&&(n.info("GitHub Copilot \u2014 reload VS Code to activate Vesper:"),n.info(' Cmd+Shift+P (macOS) / Ctrl+Shift+P (Windows/Linux) \u2192 "Developer: Reload Window"')),t&&(n.info("Claude Code \u2014 open a session in this workspace; the orchestrator"),n.info(" activates automatically via CLAUDE.md.")),console.log(),e&&n.vesperTip()}async function Qt(e={}){try{let t=e.yes||e.forceDefault,s=await Vr(e.path||process.cwd(),t);await m(s)||(n.error(`Directory not found: ${n.formatPath(s)}`),process.exit(1));let r=await _(s);r.type===E.WORKSPACE_FILE&&await jr(s,t),await Lr(s);let{selected:o,installed:i}=await Ir(e,s),a=i.filter(f=>!o.includes(f));if(o.length===0&&a.length===0){n.info("No platforms selected. Nothing to do.");return}if(!t&&i.length===0&&o.length>0&&!await ne({message:`Set up ${o.map(Xt).join(" + ")} in ${s}?`,default:!0})){n.info("Initialization cancelled.");return}a.length>0&&await Fr(s,a,t);let c=o.includes("copilot"),d=o.includes("claude"),l=null;if(c&&(l=await Nr(t)),c&&await Rr(s,r,l),d&&await Dr(s,e),c||d){await ge(s);let f=await me(s);f.length>0&&(n.warn(`Local-only file(s) are git-tracked despite .gitignore: ${f.join(", ")}`),n.warn(`Untrack them yourself (Vesper won't touch your git index): git rm --cached ${f.join(" ")}`)),(await ve(s))["pre-commit"]?.hooksDir&&(n.success("Local-only Vesper files gitignored (.vesperrc, .mcp.json, .vesper/index.db)"),n.info("Commit-hygiene git hook installed (pre-commit): keeps team roster/context/history/memory in sync with every commit"),await we(s),await ye(s),n.info("Merge strategy configured (.gitattributes): history.md unions, memory.jsonl merges entity-aware across worktrees"))}let p=c&&l?.enableMcpServer||d,u=null;p&&(u=await Be(s,!0)),Ur({copilot:c,claude:d,indexingResult:u})}catch(t){if(t.name==="ExitPromptError"){console.log(),n.info("Initialization cancelled.");return}n.error(`Initialization failed: ${t.message}`),process.exit(1)}}G();import{resolve as es,basename as Gr}from"node:path";import{checkbox as ts,select as Wr}from"@inquirer/prompts";var Zt={agents:"agents",prompts:"commands",skills:"skills"};async function Br(e,t){let s=await D(e);if(s.length===1)return s[0];s.length===0&&(n.warn('Vesper is not initialized in this workspace. Run "vespercli init" first.'),process.exit(0)),n.error(`Both Copilot and Claude targets are installed here \u2014 specify which to ${t}: --target copilot|claude`),process.exit(1)}async function qr(e={}){let t=es(e.path||process.cwd());(!e.type||!e.name)&&(n.error("Usage: vesper add <type> <name> --target claude"),n.info("Types: agents, prompts (installed as slash commands), skills"),process.exit(1));let s=Zt[e.type];s||(n.error(`Unknown asset type for --target claude: ${e.type}`),n.info(`Available types: ${Object.keys(Zt).join(", ")}`),process.exit(1));let o=(await g(t)).claude?.namePrefix??"";try{let i=await Ft(s,e.name,{namePrefix:o});n.success(`Added ${e.type}/${e.name} to the Claude plugin catalog as "${i.installedAs}"`)}catch(i){n.error(i.message),process.exit(1)}}var pe=["agents","prompts","instructions"];async function qe(e,t){let s=await se(e);return(await ee(t)).filter(o=>{let i=H(t,o);return!s.includes(i.path)})}async function Kr(e){let t=[];for(let a of pe){let c=await qe(e,a);c.length>0&&t.push({name:`${a.charAt(0).toUpperCase()+a.slice(1)} (${c.length} available)`,value:a})}if(t.length===0)return n.info("All extended assets are already added."),[];let s=await Wr({message:"Select asset type:",choices:t}),o=(await qe(e,s)).map(a=>({name:a,value:a,checked:!1}));return(await ts({message:`Select ${s} to add:`,choices:o})).map(a=>({type:s,name:a}))}async function ss(e={}){try{let t=es(e.path||process.cwd());if(await m(t)||(n.error(`Directory not found: ${n.formatPath(t)}`),process.exit(1)),(e.target||await Br(t,"add"))==="claude")return await qr({...e,path:t});if(!await he(t)){n.warn('Vesper is not initialized. Run "vespercli init" first.');return}let r=[];if(e.type&&e.name){if(e.type==="skills"){n.info("Skills are automatically added during init.");return}pe.includes(e.type)||(n.error(`Unknown asset type: ${e.type}`),n.info(`Available types: ${pe.join(", ")}`),process.exit(1));let l=await ee(e.type);l.includes(e.name)||(n.error(`Asset not found: ${e.name}`),n.info(`Available ${e.type}: ${l.join(", ")||"none"}`),process.exit(1)),r=[{type:e.type,name:e.name}]}else if(e.type){if(e.type==="skills"){n.info("Skills are automatically added during init.");return}pe.includes(e.type)||(n.error(`Unknown asset type: ${e.type}`),n.info(`Available types: ${pe.join(", ")}`),process.exit(1));let l=await qe(t,e.type);if(l.length===0){n.info(`All ${e.type} are already added.`);return}let p=l.map(f=>({name:f,value:f,checked:!1})),u=await ts({message:`Select ${e.type} to add:`,choices:p});if(u.length===0){n.info("Nothing selected.");return}r=u.map(f=>({type:e.type,name:f}))}else if(r=await Kr(t),r.length===0){n.info("Nothing selected.");return}let o=r.map(({type:l,name:p})=>H(l,p)),{added:i,skipped:a,workspaceType:c}=await yt(t,o),d=r.filter(l=>l.type==="agents"&&i.includes(H(l.type,l.name).path));for(let{name:l}of d)Re[l]&&(await $t(t,l),n.info(` Added MCP tools auto-approval for agent: ${l}`));if(i.length>0){let l=await _(t);console.log(),n.success(`Added ${i.length} asset(s):`);for(let{type:p,name:u}of r.filter(f=>i.includes(H(f.type,f.name).path)))n.info(` ${p}/${u}`);c===E.WORKSPACE_FILE&&n.info(`
27
+ Updated: ${Gr(l.settingsPath)}`),n.info(`
28
+ Reload VS Code to apply changes`)}else a.length>0&&n.info("All selected assets are already added.")}catch(t){if(t.name==="ExitPromptError"){console.log(),n.info("Cancelled.");return}n.error(`Add failed: ${t.message}`),process.exit(1)}}G();import{resolve as ns,join as Hr}from"node:path";import{readdir as Jr}from"node:fs/promises";import U from"picocolors";async function rs(e={}){let t=ns(e.path||process.cwd()),s=await g(t);if(console.log(),console.log(U.bold("Claude Code target")),!s.claude){console.log(),n.warn('Not initialized for Claude Code. Run "vesper init --target claude" first.'),console.log();return}let r=s.claude.pluginPath||Y();console.log(U.dim(`Plugin catalog: ${r}`));let o=await Nt();for(let[i,a]of Object.entries(o))console.log(),console.log(U.bold(i.charAt(0).toUpperCase()+i.slice(1))),a.length===0?console.log(U.dim(" (none installed)")):a.forEach(c=>console.log(` ${c}`));console.log(),console.log(U.bold("Project files")),console.log(" CLAUDE.md, .claude/vesper/{orchestrator,orchestration,context}.md, .mcp.json, .claude/settings.json"),console.log()}async function zr(e,t,s=!1){try{let r=await Jr(e,{withFileTypes:!0});return s||t.dir==="skills"?r.filter(i=>i.isDirectory()&&!i.name.startsWith(".")).map(i=>i.name):r.filter(i=>i.isFile()&&i.name.endsWith(t.extension)).map(i=>i.name.replace(t.extension,""))}catch{return[]}}async function os(e={}){try{let t=ns(e.path||process.cwd());await m(t)||(n.error(`Directory not found: ${n.formatPath(t)}`),process.exit(1));let s=await D(t);if(e.target==="claude")return await rs({...e,path:t});if(!e.target){if(s.length===0){console.log(),n.warn('Vesper is not initialized. Run "vespercli init" first.'),console.log();return}if(s.length===1&&s[0]==="claude")return await rs({...e,path:t});s.includes("claude")&&n.info("Claude Code target is also installed here \u2014 run `vespercli list --target claude` to see it.")}let r=await se(t);e.type&&!I[e.type]&&(n.error(`Unknown asset type: ${e.type}`),n.info(`Valid types: ${Object.keys(I).join(", ")}`),process.exit(1));let o=e.type?[e.type]:Object.keys(I);console.log(),console.log(U.bold("Assets"));for(let i of o){let a=I[i],c=i.charAt(0).toUpperCase()+i.slice(1);if(i==="skills"){let f=Pt("skills");if(r.includes(f.path)){let h=await ee("skills");console.log(),console.log(U.bold(`${c}`)),console.log(` ${h.length} skills enabled ${U.dim("(all)")}`)}continue}let d=Hr(Ye,a.dir),l=await zr(d,a,!1),u=(await ee(i)).filter(f=>{let h=H(i,f);return r.includes(h.path)});(l.length>0||u.length>0)&&(console.log(),console.log(U.bold(`${c}`)),l.forEach(f=>{console.log(` ${f} ${U.dim("(core)")}`)}),u.forEach(f=>{console.log(` ${f}`)}))}console.log()}catch(t){n.error(`List failed: ${t.message}`),process.exit(1)}}import{readFileSync as Yr,existsSync as Xr}from"node:fs";import{join as Qr}from"node:path";var as="catalog.md",Zr="mthanhtran",en="vesper",tn="main";function sn(){return`https://raw.githubusercontent.com/${Zr}/${en}/${tn}/assets/${as}`}function rn(){let e=Qr(Z,"assets",as);return Xr(e)?Yr(e,"utf-8"):null}async function nn(){try{let e=sn(),t=await fetch(e);return t.ok?t.text():null}catch{return null}}async function on(){let e=await nn();if(e)return e;let t=rn();if(t)return t;throw new Error("Catalog not available from remote or local")}async function is(){try{let e=await on();console.log(e)}catch(e){console.error(`Error loading catalog: ${e.message}`),process.exit(1)}}G();import{resolve as an,join as fs}from"node:path";import{stat as cn,readFile as gs}from"node:fs/promises";import"@inquirer/prompts";import j from"picocolors";async function $e(e){let t=await g(e);if(console.log(),n.header("vesper-indexing MCP Server (Claude Code target)"),console.log(),!t.claude){n.info("Claude Code target is not initialized. Run `vesper init --target claude` first.");return}let s=X(e),r=!1;if(await m(s))try{r=!!JSON.parse(await gs(s,"utf-8")).mcpServers?.["vesper-indexing"]}catch{r=!1}n.info(`Configured: ${r?"\u2713 yes":"\u2717 no"} (${s})`),n.info(`Server built: ${await hs()?"\u2713 yes":"\u2717 no"}`);let o=Ke(e);n.info(`Index exists: ${await m(o)?"\u2713 yes":"\u2717 no"} (shared with the Copilot target if both are installed)`);try{let{drifted:i}=await Bt(e);i.length&&(console.log(),n.warn(`MCP config drift: ${i.join(", ")} present in the live MCP config but not tracked in .vesperrc mcp.servers.`),n.warn("Run `/reinit` (or re-run workspace-learner) to resync tracking and the generated docs."))}catch{}}async function oe(e,t=!0){await Q(e,t),t&&await Te(e),n.success(`Claude Code target: vesper-indexing ${t?"enabled":"disabled"} in .mcp.json`)}function Ke(e){return fs(e,".vesper","index.db")}function ln(e){return fs(e,".vesper","indexing-status.json")}async function ms(e){let t=ln(e);try{let s=await gs(t,"utf-8");return JSON.parse(s)}catch{return null}}async function hs(){let e=W();return await m(e)}async function dn(e){try{let t=await cn(e),s=t.size,r=`${s} bytes`;return s>1024*1024?r=`${(s/(1024*1024)).toFixed(2)} MB`:s>1024&&(r=`${(s/1024).toFixed(1)} KB`),{dbSize:r,lastModified:t.mtime.toISOString()}}catch{return null}}async function cs(e,t=!1){let s=await xe(e),r=await hs(),o=Ke(e),i=await m(o),a=await ms(e);if(console.log(),n.header("vesper-indexing MCP Server"),console.log(),n.info(`Configured: ${s?"\u2713 yes":"\u2717 no"}`),n.info(`Server built: ${r?"\u2713 yes":"\u2717 no"}`),n.info(`Index exists: ${i?"\u2713 yes":"\u2717 no"}`),a)if(console.log(),a.status==="indexing")if(t){await un(e,a);return}else{let c=a.startedAt?Math.round((Date.now()-new Date(a.startedAt).getTime())/1e3):0;n.info(j.yellow("\u27F3 Indexing in progress...")),n.info(` Files processed: ${j.cyan(a.filesProcessed)}`),n.info(` Elapsed: ${j.dim(`${c}s`)}`),console.log(),n.info("Use --watch to follow indexing progress until completion")}else a.status==="error"&&(n.error(`Indexing error: ${a.error}`),n.info(` Files processed before error: ${a.filesProcessed}`));if(!s){console.log(),n.info("Run `vespercli init` to configure the MCP server");return}if(!r){console.log(),n.warn("MCP server not built. Run: cd src/mcp/vesper-indexing && npm install && npm run build");return}if(i&&!a){let c=await dn(o);c&&(console.log(),n.info(`Index size: ${c.dbSize}`),n.info(`Last modified: ${c.lastModified}`)),n.vesperTip()}else!i&&!a&&(console.log(),n.info("Index not yet created. It will be built when VS Code loads the MCP server."),console.log())}async function un(e,t){let s=n.createSpinner(`Indexing... ${t.filesProcessed} files processed`);s.start();let r=500,o=30*60*1e3,i=Date.now();return new Promise(a=>{let c=async()=>{let d=await ms(e);if(!d||d.status!=="indexing"){d?.status==="error"?s.fail(`Indexing failed: ${d.error}`):(s.succeed(`Indexing complete! ${d?.filesProcessed||"All"} files indexed`),n.info(`
29
+ \u2192 Reload VS Code to update MCP tools with the new index`),n.vesperTip()),a();return}let l=d.startedAt?Math.round((Date.now()-new Date(d.startedAt).getTime())/1e3):0;if(s.update(`Indexing... ${d.filesProcessed} files processed (${l}s)`),Date.now()-i>o){s.fail("Indexing watch timed out (30 minutes)"),a();return}setTimeout(c,r)};setTimeout(c,r)})}async function ls(e,t=!1){let s=Ke(e);if(!await m(s))n.info("No index exists. It will be built when VS Code loads the MCP server.");else if(t){let{unlink:o}=await import("node:fs/promises");await o(s),n.success("Index cleared. Reload VS Code to rebuild.")}else n.info("Incremental reindex happens automatically when files change."),n.info("Use --full to clear and rebuild the entire index.")}async function pn(e){let t=await J(e,!0);t.configured&&(n.success("MCP server enabled"),n.info(`Config: ${t.mcpPath}`),n.info("Reload VS Code to start the server"))}async function fn(e){await J(e,!1),n.success("MCP server disabled"),n.info("Reload VS Code to apply changes")}async function vs(e){let t=await _(e),s=await g(e,t);if(!Array.isArray(s.paths))return[];let r=[];for(let o of s.paths){let i=o.match(/agents\/([^/]+)\/?$/);i&&MCP_TOOLS_BY_AGENT[i[1]]&&r.push(i[1])}return r}async function gn(e){let t=await _(e),s=await g(e,t),r=await x(e,t),o=await vs(e),i=r[v]||{},a=new Set(L),c=[],d=[],l=!1;r[v]||(r[v]={});for(let u of L)i[u]||(r[v][u]=!0,c.push(u),l=!0);for(let u of o){let f=MCP_TOOLS_BY_AGENT[u]||[];for(let h of f)i[h]||(r[v][h]=!0,c.push(h),l=!0)}let p=new Set;for(let u of o)for(let f of MCP_TOOLS_BY_AGENT[u]||[])p.add(f);for(let u of Object.keys(i)){if(a.has(u))continue;let f=!1;for(let[h,O]of Object.entries(MCP_TOOLS_BY_AGENT))if(O.includes(u)){f=!0;break}f&&!p.has(u)&&(delete r[v][u],d.push(u),l=!0)}if(s.mcp=s.mcp||{},s.mcp.syncedAt=new Date().toISOString(),s.mcp.approvedAgents=o,s.mcp.toolCount=Object.keys(r[v]).length,l&&await P(e,r),await C(e,s),console.log(),n.header("MCP Tools Sync"),console.log(),c.length===0&&d.length===0)n.success("Already in sync");else{if(c.length>0){n.success(`Added ${c.length} tool(s)`);let u=c.filter(f=>a.has(f));u.length>0&&n.info(` Core: ${u.length} tools`);for(let f of o){let h=c.filter(O=>(MCP_TOOLS_BY_AGENT[f]||[]).includes(O));h.length>0&&n.info(` ${f}: ${h.length} tools`)}}d.length>0&&n.info(`Removed ${d.length} orphaned tool(s)`)}n.info(`
30
+ Total approved tools: ${s.mcp.toolCount}`),o.length>0&&n.info(`Agents with tools: ${o.join(", ")}`),l&&n.info(`
31
+ Reload VS Code to apply changes`)}async function mn(e){let t=await _(e),s=await g(e,t),o=(await x(e,t))[v]||{},i=Object.keys(o).length,a=await vs(e);console.log(),n.header("MCP Tool Approval Status"),console.log();let c=L.filter(p=>o[p]);if(n.info(`Core tools: ${c.length}/${L.length} approved`),a.length>0){console.log(),n.info("Agent tools:");for(let p of a){let u=MCP_TOOLS_BY_AGENT[p]||[],f=u.filter(O=>o[O]),h=f.length===u.length?j.green("\u2713"):j.yellow("\u26A0");n.info(` ${h} ${p}: ${f.length}/${u.length} approved`)}}let d=[...L];for(let p of a)d.push(...MCP_TOOLS_BY_AGENT[p]||[]);let l=d.filter(p=>!o[p]);console.log(),n.info(`Total approved: ${i} tools`),l.length>0?(console.log(),n.warn(`${l.length} tools missing approval`),n.info("Run `vespercli mcp sync` to fix")):s.mcp?.syncedAt&&n.info(`Last synced: ${s.mcp.syncedAt}`)}function ws(){return Object.keys(V).filter(e=>!K.includes(e))}async function hn(e,t){t||(n.error("Server name required. Usage: vespercli mcp add <server>"),n.info(`Available servers: ${ws().join(", ")}`),process.exit(1)),console.log(),n.header("Add MCP Server"),console.log();let s=await Ot(e,t);if(!s.added){s.error==="Already configured"?n.info(`MCP server '${t}' is already configured`):(n.error(s.error),process.exit(1));return}n.success(`Added MCP server: ${t}`),s.tools.length>0&&n.info(`Approved ${s.tools.length} tool(s) for auto-execution`),n.info(`
32
+ Reload VS Code to activate the MCP server`)}async function vn(e,t){t||(n.error("Server name required. Usage: vespercli mcp remove <server>"),process.exit(1)),console.log(),n.header("Remove MCP Server"),console.log();let s=await It(e,t);if(!s.removed){n.info(`MCP server '${t}' is not configured`);return}n.success(`Removed MCP server: ${t}`),s.tools.length>0&&n.info(`Removed ${s.tools.length} tool(s) from auto-approval`),n.info(`
33
+ Reload VS Code to deactivate the MCP server`)}async function wn(e){let t=await _(e),s=await g(e,t),r=await F(e);console.log(),n.header("MCP Servers"),console.log();let o=s.mcp?.servers||[],i=Object.keys(r.servers||{});n.info("Available servers:");for(let[c,d]of Object.entries(V)){let p=i.includes(c)?j.green("\u2713"):j.dim("\u25CB"),u=d.tools?.length||0;n.info(` ${p} ${c} (${u} tools)`)}let a=i.filter(c=>!V[c]);if(a.length>0){console.log(),n.info("Custom servers:");for(let c of a)n.info(` ${j.blue("\u25C6")} ${c}`)}console.log(),n.info(`Installed: ${i.length} server(s)`)}async function ds(e,t){t||(n.error("Server name required. Usage: vespercli mcp add <server> --target claude"),n.info(`Available servers: ${ws().join(", ")}`),process.exit(1));let s=await Ut(e,t);if(!s.added){s.error==="Already configured"?n.info(`MCP server '${t}' is already configured for the Claude Code target`):n.error(s.error);return}n.success(`Added MCP server: ${t} (Claude Code target)`),n.info(`
34
+ Reload the Claude Code session to activate the MCP server`)}async function us(e,t){t||(n.error("Server name required. Usage: vespercli mcp remove <server> --target claude"),process.exit(1));let s=await Gt(e,t);if(s.error){n.error(s.error);return}if(!s.removed){n.info(`MCP server '${t}' is not configured for the Claude Code target`);return}n.success(`Removed MCP server: ${t} (Claude Code target)`),n.info(`
35
+ Reload the Claude Code session to deactivate the MCP server`)}async function ps(e){let{configured:t,custom:s}=await Wt(e);console.log(),n.header("MCP Servers (Claude Code target)"),console.log(),n.info("Available servers:");for(let[r,o]of Object.entries(V)){let a=t.includes(r)?j.green("\u2713"):j.dim("\u25CB"),c=o.tools?.length||0;n.info(` ${a} ${r} (${c} tools)`)}if(s.length>0){console.log(),n.info("Custom servers:");for(let r of s)n.info(` ${j.blue("\u25C6")} ${r}`)}console.log(),n.info(`Installed: ${t.length} server(s)`)}async function ys(e,t,s={}){let r=an(s.path||process.cwd());await m(r)||(n.error(`Directory not found: ${r}`),process.exit(1));let o=await D(r),i=s.target?[s.target]:o.length?o:["copilot"],a=i.includes("copilot"),c=i.includes("claude");if(c&&!a)switch(e){case"enable":return await oe(r,!0);case"disable":return await oe(r,!1);case"sync":return await oe(r,!0);case"add":return await ds(r,t);case"remove":return await us(r,t);case"list":return await ps(r);case"status":return await $e(r);case"reindex":return await ls(r,s.full);default:return e&&n.warn(`'${e}' is not applicable to the Claude Code target \u2014 showing status instead.`),await $e(r)}let d=a&&c;switch(e){case"status":await cs(r,s.watch),d&&await $e(r);break;case"add":await hn(r,t),d&&await ds(r,t);break;case"remove":await vn(r,t),d&&await us(r,t);break;case"list":await wn(r),d&&await ps(r);break;case"reindex":await ls(r,s.full);break;case"enable":await pn(r),d&&await oe(r,!0);break;case"disable":await fn(r),d&&await oe(r,!1);break;case"sync":await gn(r),d&&await oe(r,!0);break;case"approve":await mn(r);break;default:await cs(r,s.watch),d&&await $e(r)}}import{resolve as yn}from"node:path";async function Ss(e,t,s,r={}){let o=yn(r.path||process.cwd());if(!e){_s();return}switch(e){case"add":await _n(o,t,s);break;case"remove":await Sn(o,t,s);break;case"list":await xn(o,t);break;default:n.error(`Unknown subcommand: ${e}`),_s()}}async function _n(e,t,s){if(!t){n.error("Setting key required"),n.info("Usage: vespercli settings add <setting-key> <value>");return}switch(t){case"github.copilot.chat.additionalReadAccessPaths":case"additionalReadAccessPaths":case"read-access":if(!s){n.error("Path value required"),n.info("Usage: vespercli settings add read-access <path>");return}let r=await kt(e,s);n.success(`Added "${s}" to additional read access paths`),n.info(`Current paths: ${r.length>0?r.join(", "):"(none)"}`);break;default:n.error(`Unknown setting: ${t}`),n.info("Supported settings:"),n.info(" - read-access (github.copilot.chat.additionalReadAccessPaths)")}}async function Sn(e,t,s){if(!t){n.error("Setting key required"),n.info("Usage: vespercli settings remove <setting-key> <value>");return}switch(t){case"github.copilot.chat.additionalReadAccessPaths":case"additionalReadAccessPaths":case"read-access":if(!s){n.error("Path value required"),n.info("Usage: vespercli settings remove read-access <path>");return}let r=await Ct(e,s);n.success(`Removed "${s}" from additional read access paths`),n.info(`Current paths: ${r.length>0?r.join(", "):"(none)"}`);break;default:n.error(`Unknown setting: ${t}`),n.info("Supported settings:"),n.info(" - read-access (github.copilot.chat.additionalReadAccessPaths)")}}async function xn(e,t){if(!t){n.info("Managed settings:"),n.info(" - read-access (github.copilot.chat.additionalReadAccessPaths)"),n.info(""),n.info("Use: vespercli settings list <setting-key>");return}switch(t){case"github.copilot.chat.additionalReadAccessPaths":case"additionalReadAccessPaths":case"read-access":let s=await At(e);n.info(`${S}:`),s.length===0?n.info(" (empty)"):s.forEach(r=>n.info(` - ${r}`));break;default:n.error(`Unknown setting: ${t}`),n.info("Supported settings:"),n.info(" - read-access (github.copilot.chat.additionalReadAccessPaths)")}}function _s(){n.info("Usage: vespercli settings <subcommand> [setting-key] [value]"),n.info(""),n.info("Subcommands:"),n.info(" add <setting-key> <value> Add a value to an array setting"),n.info(" remove <setting-key> <value> Remove a value from an array setting"),n.info(" list [setting-key] List current values"),n.info(""),n.info("Supported settings:"),n.info(" read-access github.copilot.chat.additionalReadAccessPaths"),n.info(""),n.info("Examples:"),n.info(" vespercli settings add read-access /path/to/external/repo"),n.info(" vespercli settings remove read-access /path/to/external/repo"),n.info(" vespercli settings list read-access")}G();import{resolve as xs}from"node:path";async function kn(e={}){let t=xs(e.path||process.cwd()),s=await g(t);if(!s.claude){n.warn('Claude Code target is not initialized. Run "vesper init --target claude" first.');return}console.log(),n.info("Refreshing Claude Code plugin catalog and orchestrator playbook...");let{pluginDir:r,counts:o}=await Pe({namePrefix:s.claude.namePrefix||"",version:e.version||"0.0.0"});n.success(`Plugin catalog refreshed: ${r}`),n.info(` agents: ${o.agents}, commands: ${o.commands}, skills: ${o.skills}`);let i=await Ee(t);n.success(`Orchestrator playbook refreshed (.claude/vesper/orchestrator.md: ${i.orchestrator})`),n.info("Team roster (.claude/vesper/orchestration.md) and project context (.claude/vesper/context.md) are left alone \u2014 they belong to this project.")}async function ks(e={}){try{let t=xs(e.path||process.cwd());await m(t)||(n.error(`Directory not found: ${n.formatPath(t)}`),process.exit(1));let s=e.target?[e.target]:await D(t);if(s.length===0){n.warn('Vesper is not initialized. Run "vespercli init" first.');return}s.includes("claude")&&await kn({...e,path:t}),s.includes("copilot")&&(console.log(),n.info("Copilot assets are linked from the package, not copied."),n.info("Update the vesper package to get the latest assets:"),n.dim(" npm update -g @mthanh/vespercli"),console.log())}catch(t){n.error(`Update failed: ${t.message}`),process.exit(1)}}G();import{resolve as Cn,join as He}from"node:path";async function An(e){let t=await m(He(Ce(e),"orchestration.md")),s=await m(He(e,".github","copilot-instructions.md"));return{claude:t,copilot:s}}async function Pn(e,t){if(!await m(e))return;let{claude:s,copilot:r}=await An(e);if(!s&&!r){t||n.info("Not a vesperized workspace \u2014 nothing to bootstrap. Run `vespercli init` to set up.");return}let o=[];s&&(await Q(e,!0),o.push(".mcp.json regenerated for this worktree (Claude target)")),r&&await xe(e)&&(await J(e,!0),o.push(".vscode/mcp.json refreshed (Copilot target)"));let i=He(e,".vesper","index.db");if(!await m(i)){let c=await Be(e,!1);c.success&&o.push(`code index built (${c.filesIndexed} files)`)}await ge(e);let a=await me(e);if(a.length>0&&n.warn(`Local-only file(s) git-tracked despite .gitignore: ${a.join(", ")} \u2014 untrack with: git rm --cached ${a.join(" ")}`),await ve(e),await we(e),await ye(e),o.push("gitignore + git hooks + merge strategy ensured"),!t){n.success("Worktree bootstrap complete");for(let c of o)n.info(` ${c}`)}}async function Cs(e,t={}){let s=Cn(t.path||process.cwd()),r=!!t.quiet;switch(e){case"bootstrap":case void 0:await Pn(s,r);break;default:n.error(`Unknown subcommand: ${e}. Usage: vespercli worktree bootstrap`),process.exit(1)}}var On=$n(import.meta.url),In=Je(On);function Mn(e){let t=e;for(;t!==Je(t);){let s=As(t,"package.json");if(bn(s))return s;t=Je(t)}return As(e,"..","..","package.json")}var Dn=Mn(In),ze=JSON.parse(Tn(Dn,"utf-8")),R=new En;R.name("vespercli").description("Vesper VS Code Agent Suite \u2014 manage GitHub Copilot agents, prompts, instructions, and skills").version(ze.version,"-v, --version","Output the current version");R.command("init").description("Initialize vesper for one or more platforms (GitHub Copilot and/or Claude Code) in this workspace").option("-p, --path <path>","Workspace root directory",process.cwd()).option("-y, --yes","Skip follow-up prompts (not the platform selection)").option("-f, --force","Force re-initialization (skips follow-up prompts)").option("--force-default","Use all default values for follow-up prompts (not the platform selection)").option("--target <targets>","Platform(s) to set up: copilot, claude, a comma list (copilot,claude), or all. Multi-select prompt if omitted.").action(e=>Qt({...e,version:ze.version}));R.command("add").description("Add extended assets \u2014 to VS Code settings (Copilot) or the Claude Code plugin catalog. Target is auto-detected from the workspace when omitted.").argument("[type]","Asset type (agents, prompts, instructions, skills)").argument("[name]","Asset name (specific asset to add)").option("--path <path>","Workspace root directory",process.cwd()).option("--target <target>","Install target: copilot or claude (auto-detected if omitted)").action((e,t,s)=>ss({type:e,name:t,...s}));R.command("reset").description("Remove the Vesper install \u2014 Copilot settings or the Claude Code target. Target is auto-detected from the workspace when omitted.").option("--path <path>","Workspace root directory",process.cwd()).option("-y, --yes","Skip confirmation prompts").option("--target <target>","Install target: copilot or claude (auto-detected if omitted)").action(zt);R.command("list").alias("ls").description("List enabled assets").argument("[type]","Filter by asset type (agents, prompts, instructions, skills)").option("--path <path>","Workspace root directory",process.cwd()).option("--target <target>","Install target: copilot or claude (omit to see all installed targets)").action((e,t)=>os({type:e,...t}));R.command("update").description("Refresh installed targets \u2014 the Claude Code plugin catalog + orchestrator playbook, and/or the Copilot package-link note. Auto-detected from the workspace when omitted.").option("--path <path>","Workspace root directory",process.cwd()).option("--target <target>","Install target: copilot or claude (auto-detected if omitted)").action(e=>ks({...e,version:ze.version}));R.command("catalog").description("Show the Vesper catalog (agents, dependencies, requirements)").action(is);R.command("mcp").description("Manage MCP servers and tool auto-approval").argument("[subcommand]","Subcommand: status, add, remove, list, sync, approve, reindex, enable, disable").argument("[argument]","Argument for subcommand (e.g., server name for add/remove)").option("--path <path>","Workspace root directory",process.cwd()).option("--full","Full reindex (clears existing index)").option("-w, --watch","Watch indexing progress until completion").option("--target <target>","Install target: copilot, claude, or omit for all installed targets").action((e,t,s)=>ys(e,t,s));R.command("settings").description("Manage VS Code settings").argument("[subcommand]","Subcommand: add, remove, list").argument("[setting-key]","Setting key (e.g., read-access)").argument("[value]","Value to add/remove").option("--path <path>","Workspace root directory",process.cwd()).action((e,t,s,r)=>Ss(e,t,s,r));R.command("worktree").description("Bootstrap a git worktree with Vesper's local-only artifacts (.mcp.json, code index, gitignore, git hooks)").argument("[subcommand]","Subcommand: bootstrap (default)").option("--path <path>","Workspace root directory",process.cwd()).option("-q, --quiet","Suppress non-error output (used by hooks/tasks)").action((e,t)=>Cs(e,t));R.addHelpText("after",`
15
36
  Examples:
16
37
  $ vespercli init Pick platform(s) to set up (multi-select), then initialize
17
38
  $ vespercli init --target copilot,claude Set up both platforms in one run
@@ -36,6 +57,7 @@ Examples:
36
57
  $ vespercli settings add read-access /path Add path to read access
37
58
  $ vespercli settings list read-access Show read access paths
38
59
  $ vespercli reset Remove all Vesper paths from settings
60
+ $ vespercli worktree bootstrap Regenerate local-only files in a fresh worktree (no-op if not vesperized)
39
61
 
40
62
  Multi-platform notes:
41
63
  $ vespercli init On re-init, installed platforms are pre-checked; uncheck to remove
@@ -45,4 +67,4 @@ Multi-platform notes:
45
67
 
46
68
  Documentation:
47
69
  https://github.com/mthanhtran/vesper
48
- `);I.parse();
70
+ `);R.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mthanh/vespercli",
3
- "version": "1.4.0",
3
+ "version": "1.5.1",
4
4
  "description": "Vesper Agent Suite — CLI to manage AI agents, prompts, instructions, and skills for GitHub Copilot (VS Code) and Claude Code",
5
5
  "type": "module",
6
6
  "main": "./src/cli/index.js",
@@ -19,7 +19,7 @@
19
19
  "scripts": {
20
20
  "start": "node bin/vesper.js",
21
21
  "dev": "VESPER_DEV=true node bin/vesper.js",
22
- "test": "echo \"No tests yet\" && exit 0",
22
+ "test": "vitest run",
23
23
  "build:cli": "esbuild src/cli/index.js --bundle --platform=node --format=esm --minify --outfile=dist/cli.min.js --external:@inquirer/prompts --external:commander --external:picocolors --external:strip-json-comments",
24
24
  "build:mcp": "cd src/mcp/vesper-indexing && npm install && npm run build",
25
25
  "build": "npm run build:cli && npm run build:mcp",
@@ -57,6 +57,7 @@
57
57
  "strip-json-comments": "^5.0.3"
58
58
  },
59
59
  "devDependencies": {
60
- "esbuild": "^0.20.0"
60
+ "esbuild": "^0.20.0",
61
+ "vitest": "^4.1.10"
61
62
  }
62
63
  }