@macintacos/caret 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +19 -14
  3. package/bin/caret +1 -1
  4. package/commands/doctor.md +139 -0
  5. package/commands/plan.md +25 -0
  6. package/dist/cli.js +6102 -17980
  7. package/opencode/caret.plugin.ts +6 -5
  8. package/opencode/commands/doctor.md +120 -0
  9. package/opencode/commands/plan.md +24 -0
  10. package/package.json +1 -1
  11. package/ui/dist/assets/{angular-html-CNIx69MF.js → angular-html-BECXXPyr.js} +1 -1
  12. package/ui/dist/assets/{angular-ts-B6ob15kD.js → angular-ts-CJKAKY9F.js} +1 -1
  13. package/ui/dist/assets/{apl-BzQg5wKE.js → apl-CCcfDDqZ.js} +1 -1
  14. package/ui/dist/assets/{astro-DQ6PiTON.js → astro-DKCnAnVR.js} +1 -1
  15. package/ui/dist/assets/{blade-DdGMUzbN.js → blade-DQ_JdT2N.js} +1 -1
  16. package/ui/dist/assets/{c-DhrAH2di.js → c-D3TwszVj.js} +1 -1
  17. package/ui/dist/assets/{chapel-BIJH6n90.js → chapel-C-2sPcCX.js} +1 -1
  18. package/ui/dist/assets/{cobol-CR-dFJ1T.js → cobol-BPmo_4f_.js} +1 -1
  19. package/ui/dist/assets/{coffee-DWT27RO5.js → coffee-DMTsNDVt.js} +1 -1
  20. package/ui/dist/assets/{cpp-CuONTEvg.js → cpp-BJr6_Y8R.js} +1 -1
  21. package/ui/dist/assets/{crystal-Bvc0l-OM.js → crystal-pIWESUkD.js} +1 -1
  22. package/ui/dist/assets/{css-BYejQHVV.js → css-DRd9Q4Li.js} +1 -1
  23. package/ui/dist/assets/{dist-COogZ9jg.js → dist-BFQBMwmz.js} +1 -1
  24. package/ui/dist/assets/{dist-BgZhLp84.js → dist-BGfsV7n2.js} +1 -1
  25. package/ui/dist/assets/{dist-Cuerw0_4.js → dist-BJ7SLVNC.js} +1 -1
  26. package/ui/dist/assets/{dist-D-lJ6tIg.js → dist-BNr0c85A.js} +1 -1
  27. package/ui/dist/assets/{dist-C-FIXuZc.js → dist-C6t67BjE.js} +1 -1
  28. package/ui/dist/assets/{dist-Bn_ExXCc.js → dist-CD25BkNS.js} +1 -1
  29. package/ui/dist/assets/{dist-BbAsmjOe.js → dist-CU5aMlNo.js} +1 -1
  30. package/ui/dist/assets/{dist-CCPLuvXB.js → dist-DoJTqy3z.js} +1 -1
  31. package/ui/dist/assets/{dist-RKZBj-sl.js → dist-RKKeH1zs.js} +1 -1
  32. package/ui/dist/assets/{dist-DV7t-p4N.js → dist-aKlRxpD_.js} +1 -1
  33. package/ui/dist/assets/{edge-B_-8Eolr.js → edge-DeNk4F2G.js} +1 -1
  34. package/ui/dist/assets/{elixir-CAhwbI74.js → elixir-DHc-DOO8.js} +1 -1
  35. package/ui/dist/assets/{elm-yg-VSwEl.js → elm-CJRqEcvz.js} +1 -1
  36. package/ui/dist/assets/{erb-CIMOpWGO.js → erb-BEWGTHDA.js} +1 -1
  37. package/ui/dist/assets/{git-rebase-DI22snkc.js → git-rebase-DzlcWhg9.js} +1 -1
  38. package/ui/dist/assets/{glimmer-js-CZHZNAs-.js → glimmer-js-B-aWCRIZ.js} +1 -1
  39. package/ui/dist/assets/{glimmer-ts-C2rq-JGq.js → glimmer-ts-DcjmPyQn.js} +1 -1
  40. package/ui/dist/assets/{glsl-ByXN6hIN.js → glsl-C9FOT-Uv.js} +1 -1
  41. package/ui/dist/assets/{graphql-DiiJwLqR.js → graphql-BgKSoRp0.js} +1 -1
  42. package/ui/dist/assets/{hack-hQSSm1D1.js → hack-BOedpUUE.js} +1 -1
  43. package/ui/dist/assets/{haml-cf9hcOgw.js → haml-Cpngw1vd.js} +1 -1
  44. package/ui/dist/assets/{handlebars-B3tg892p.js → handlebars-CpW1IyBg.js} +1 -1
  45. package/ui/dist/assets/{html-CkIr2qlC.js → html-CV142D8s.js} +1 -1
  46. package/ui/dist/assets/{html-derivative-U1EOyk5J.js → html-derivative-Df7h1Nuw.js} +1 -1
  47. package/ui/dist/assets/{http-ek0-hDT8.js → http-Cneddv9N.js} +1 -1
  48. package/ui/dist/assets/{hurl-DbN52Bpk.js → hurl-D6TS55N6.js} +1 -1
  49. package/ui/dist/assets/{index-uBaTjG1U.js → index-Ci9yCNtV.js} +248 -214
  50. package/ui/dist/assets/index-t6i4na1R.css +1 -0
  51. package/ui/dist/assets/{java-DXEu0FGs.js → java-BicD3zQH.js} +1 -1
  52. package/ui/dist/assets/{javascript-Bi95ibpN.js → javascript-l6vKHWBV.js} +1 -1
  53. package/ui/dist/assets/{jinja-BcKnkqjY.js → jinja-BJF2iot2.js} +1 -1
  54. package/ui/dist/assets/{jison-CFaHQ730.js → jison-DiXPFJAT.js} +1 -1
  55. package/ui/dist/assets/{json--ulVurkL.js → json-BDRuI4UV.js} +1 -1
  56. package/ui/dist/assets/{jsx-ZonywBBD.js → jsx-BvfdkIOy.js} +1 -1
  57. package/ui/dist/assets/{julia-Bnt3bGqT.js → julia-bXAhreI5.js} +1 -1
  58. package/ui/dist/assets/{just-CBpil8Tz.js → just-BOxCfXDg.js} +1 -1
  59. package/ui/dist/assets/{latex-D-qwKUqq.js → latex-B9OiTBLF.js} +1 -1
  60. package/ui/dist/assets/{liquid-Bu8cI_b1.js → liquid-DuLKDeWE.js} +1 -1
  61. package/ui/dist/assets/{lua-DO_5Mymc.js → lua-Dbh9FQm_.js} +1 -1
  62. package/ui/dist/assets/{marko-DJfs6dcc.js → marko--tjEBgDM.js} +1 -1
  63. package/ui/dist/assets/{mdc-CnkU1WJT.js → mdc-ByNJpl3m.js} +1 -1
  64. package/ui/dist/assets/{nginx-B5LxXEA3.js → nginx-D4wsmFK9.js} +1 -1
  65. package/ui/dist/assets/{nim-DLTorTuD.js → nim-Cy8RxisP.js} +1 -1
  66. package/ui/dist/assets/{org-DnNvsXCU.js → org-CAm7o61d.js} +1 -1
  67. package/ui/dist/assets/{perl-Q5Q2rA31.js → perl-BAvaFGKe.js} +1 -1
  68. package/ui/dist/assets/{php-S65hjGBt.js → php-DpAf3w7u.js} +1 -1
  69. package/ui/dist/assets/{pug-k-MB8PEo.js → pug-Dm7otyJU.js} +1 -1
  70. package/ui/dist/assets/{qml-Bf9cLRPv.js → qml-D4rWQQKC.js} +1 -1
  71. package/ui/dist/assets/{r-Cr3hDQkZ.js → r-DMKUX8qf.js} +1 -1
  72. package/ui/dist/assets/{razor-BO5-wpmp.js → razor-BIUJkuf_.js} +1 -1
  73. package/ui/dist/assets/{regexp-ffQ9gsih.js → regexp-D8W_pVHj.js} +1 -1
  74. package/ui/dist/assets/{rst-B4AQC5xj.js → rst-aFr0DP5H.js} +1 -1
  75. package/ui/dist/assets/{ruby-Dr8kfvLX.js → ruby-BzH6kUKr.js} +1 -1
  76. package/ui/dist/assets/{sas-Kuo2pLeL.js → sas-CDk9DyCV.js} +1 -1
  77. package/ui/dist/assets/{scss-Ci63BQ8y.js → scss-DABbvU5W.js} +1 -1
  78. package/ui/dist/assets/{shellscript-DBh4gnVx.js → shellscript-B0ObP3K-.js} +1 -1
  79. package/ui/dist/assets/{shellsession-L5KFvHI3.js → shellsession-2sv3Jq0j.js} +1 -1
  80. package/ui/dist/assets/{soy-D6F5ilyd.js → soy-irSRV4oq.js} +1 -1
  81. package/ui/dist/assets/{sql-xwRblxjL.js → sql-DJCHoKvP.js} +1 -1
  82. package/ui/dist/assets/{stata-l8sBIGPT.js → stata-a8YnzbIc.js} +1 -1
  83. package/ui/dist/assets/{surrealql-DL2sOSzB.js → surrealql-DdXPOg8s.js} +1 -1
  84. package/ui/dist/assets/{svelte-Dp5d2Ja3.js → svelte-ClAKUEZR.js} +1 -1
  85. package/ui/dist/assets/{templ-B3LfgeSM.js → templ-NUCvvUBA.js} +1 -1
  86. package/ui/dist/assets/{tex-CfLQjgEV.js → tex-DwZeSAfC.js} +1 -1
  87. package/ui/dist/assets/{ts-tags-BCfi6Eh_.js → ts-tags-CFJEHYY_.js} +1 -1
  88. package/ui/dist/assets/{tsx-BXhT7ita.js → tsx-B934yX2T.js} +1 -1
  89. package/ui/dist/assets/{twig-t6tdMpRg.js → twig-NFkkOj3w.js} +1 -1
  90. package/ui/dist/assets/{typescript-CFIlDlxn.js → typescript-7bmMC_xU.js} +1 -1
  91. package/ui/dist/assets/{typst-CVQ9ief2.js → typst-BQEjp9tn.js} +1 -1
  92. package/ui/dist/assets/{vue-D92U7PL6.js → vue-JqD9ieOF.js} +1 -1
  93. package/ui/dist/assets/{vue-html-B_-4d7cG.js → vue-html-CT4XQRX1.js} +1 -1
  94. package/ui/dist/assets/{vue-vine-LaG8znAe.js → vue-vine-DIR27Dmn.js} +1 -1
  95. package/ui/dist/assets/{xml-DgAE0jfV.js → xml-DhsMbw-1.js} +1 -1
  96. package/ui/dist/assets/{xsl-DkD8aIzS.js → xsl-BvqsVUg9.js} +1 -1
  97. package/ui/dist/assets/{yaml-CEG92fN8.js → yaml-C8eWjK_Q.js} +1 -1
  98. package/ui/dist/index.html +2 -2
  99. package/commands/debug.md +0 -138
  100. package/commands/discovery.md +0 -35
  101. package/opencode/commands/debug.md +0 -59
  102. package/opencode/commands/discovery.md +0 -31
  103. package/ui/dist/assets/index-CAl4rX7_.css +0 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "caret",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "Review, annotate, and approve Claude Code plans in a local web UI.",
5
5
  "author": { "name": "macintacos" },
6
6
  "homepage": "https://github.com/macintacos/caret",
package/README.md CHANGED
@@ -17,7 +17,9 @@ Want to develop `caret` rather than use it? Start with [CONTRIBUTING.md](CONTRIB
17
17
 
18
18
  ## Install
19
19
 
20
- `caret` needs [`bun`](https://bun.sh) on your `PATH` — it runs from a `bun` bundle.
20
+ ```sh
21
+ bunx --no-cache @macintacos/caret@latest install
22
+ ```
21
23
 
22
24
  > [!NOTE]
23
25
  > `caret` supports macOS and Linux, where the review UI can run as a long-lived login
@@ -25,10 +27,6 @@ Want to develop `caret` rather than use it? Start with [CONTRIBUTING.md](CONTRIB
25
27
  > [`doc/CONFIGURING.md`](doc/CONFIGURING.md#platform-support) for what differs on each
26
28
  > platform and what to fall back on.
27
29
 
28
- ```sh
29
- bunx --no-cache @macintacos/caret@latest install
30
- ```
31
-
32
30
  Assuming that you installed it as a long-lived service (the default), you can navigate to
33
31
  <http://caret.localhost:42718> to see the `caret` UI.
34
32
 
@@ -37,6 +35,8 @@ After installing:
37
35
  1. **Restart the agent.** OpenCode installs the plugin package on its next start.
38
36
  2. **Run `/caret:demo`.** It presents a short demo plan that points at files in the repo
39
37
  you run it from, so you can exercise the whole flow before a real one arrives.
38
+ 3. **Run `/caret:plan <what you want done>`** to plan a real change and review it in
39
+ `caret` before the agent implements it.
40
40
 
41
41
  ### Running `caret` yourself
42
42
 
@@ -61,7 +61,8 @@ bunx --no-cache @macintacos/caret@latest install --uninstall # remove
61
61
  ```
62
62
 
63
63
  `caret`'s UI is designed to check for updates, at most once a day. When a newer `caret` is
64
- out, the review UI says so once: a toast on load, a mark on the settings button, and a
64
+ out, the review UI says so once: a toast on load that opens **What's new** (the skipped
65
+ release notes or trunk commits), a mark on the settings button, and a
65
66
  **Settings → Updates** pane naming the version and the exact command to take it.
66
67
 
67
68
  Turn the check off from that same pane, or by hand in
@@ -89,10 +90,12 @@ your browser instead of the terminal prompt. There you:
89
90
  and re-present.
90
91
 
91
92
  > [!TIP]
92
- > You don't have to wait to be intercepted: `caret` gives both agents a plan-review tool
93
- > they can call directly — `review_plan` in Claude Code (from the plugin's MCP server) and
94
- > `caret_review_plan` in OpenCode — so a skill of your own can route its plan through the
95
- > same review UI. The tool is for plans only; see
93
+ > You don't have to wait to be intercepted: `/caret:plan <what you want done>` asks the
94
+ > agent for a plan and routes it straight to the review UI. In OpenCode it runs on the
95
+ > `plan` agent, so switch to `build` to implement once you approve. A skill of your own
96
+ > can do the same with the plan-review tool `caret` gives both agents — `review_plan` in
97
+ > Claude Code (from the plugin's MCP server) and `caret_review_plan` in OpenCode. The tool
98
+ > is for plans only; see
96
99
  > [`doc/ARCHITECTURE.md`](doc/ARCHITECTURE.md#calling-the-review-tool-from-your-own-skill).
97
100
 
98
101
  ## Configuration
@@ -116,10 +119,12 @@ Two more live at the repo root:
116
119
 
117
120
  ## Diagnostics
118
121
 
119
- - `/caret:discovery` prints a one-shot, read-only diagnostics snapshot of your install —
120
- always redacted, and it never contains plan, prompt, or feedback bodies, nor any log
121
- contents.
122
- - `/caret:debug` reviews the current session's plans and recent errors.
122
+ - `/caret:doctor` runs `caret doctor`: a one-shot, read-only check of your install —
123
+ what's wrong, how to fix it, and the state it read that from. Always redacted, and it
124
+ never contains plan, prompt, or feedback bodies, nor any log message, error or stack
125
+ text.
126
+ - `caret doctor --bundle` archives the raw logs and review records when a maintainer needs
127
+ them. That archive is **not** redacted, so caret asks before writing it.
123
128
 
124
129
  ## License
125
130
 
package/bin/caret CHANGED
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # caret plugin entrypoint shim (EXC-643). This is the ONE file Claude Code's
4
4
  # hooks invoke — `${CLAUDE_PLUGIN_ROOT}/bin/caret <subcommand>` (see
5
- # hooks/hooks.json and commands/discovery.md). It is committed and shipped in
5
+ # hooks/hooks.json and commands/doctor.md). It is committed and shipped in
6
6
  # every install; it resolves the actual caret runtime from whatever the install
7
7
  # method placed beside it:
8
8
  #
@@ -0,0 +1,139 @@
1
+ ---
2
+ description: Diagnose this caret install — run caret doctor, relay each failing check's remedy, and present the report ready to share
3
+ ---
4
+
5
+ caret's `doctor` subcommand renders a verdict over a one-shot, read-only snapshot of the
6
+ local install: a `checks:` block naming what is wrong and how to fix it, then the state it
7
+ read that from — running caret processes, daemon identity, lock/port state, effective
8
+ settings, review counts, the agent adapter's install-state probe (plugin version, enabled
9
+ state, and whether a manual hook sits in the agent's user settings), log sizes and error
10
+ counts, recent failures grouped by review with their codes, install/runtime info, and
11
+ system basics. The report is **always redacted** (home paths become `~`, usernames in
12
+ foreign home paths are censored) and never contains plan, prompt, or feedback bodies, nor
13
+ any log message, error or stack text — it exists to be shared.
14
+
15
+ ## 1. Run it
16
+
17
+ First ask the user (via `AskUserQuestion`) which format they want:
18
+
19
+ - **JSON** — for feeding to tooling.
20
+ - **Human-readable** — for scanning in the conversation.
21
+
22
+ Then run the matching invocation:
23
+
24
+ ```bash
25
+ "${CLAUDE_PLUGIN_ROOT}/bin/caret" doctor --json # JSON
26
+ "${CLAUDE_PLUGIN_ROOT}/bin/caret" doctor # human-readable
27
+ ```
28
+
29
+ The exit code is the verdict: `0` every check passed, `1` at least one failed, `2` no
30
+ report — doctor could not produce one, or a `--bundle` run had no terminal to ask consent
31
+ at and stopped before collecting anything. On `2`, present the exit code and stderr
32
+ instead — and if the binary itself is missing (a source checkout that has never been
33
+ built), say so and point at `mise run build` (or `mise run build --install`).
34
+
35
+ ## 2. Relay each failing check
36
+
37
+ A failing check already carries the remedy that closes it; relay it rather than inventing
38
+ one. What each id means:
39
+
40
+ | id | what failed | relay |
41
+ | --- | --- | --- |
42
+ | `daemon-reachable` | a caret service is recorded but the daemon did not answer, or the effective port answers as something other than caret | the check's remedy verbatim, then offer to read any log it names |
43
+ | `daemon-lock` | the lock names a dead pid, or a port caret is not configured to bind | the check's remedy verbatim |
44
+ | `agent-install` | the agent the check names does not have caret enabled | `caret install` |
45
+ | `log-errors` | a live log wrote an NDJSON error record in the last 24h; the detail names which log and when it last erred | step 4 |
46
+ | `opencode-caret-version` | OpenCode would load a caret behind the published one | the check's remedy verbatim |
47
+
48
+ An `unknown` check is not a failure: it names its own `reason` — no network, an unreadable
49
+ config, or a report section that never collected, which also shows as `<name> error: …`
50
+ (`"error": "…"` under `--json`) and leaves the check with no detail. A doctor run offline
51
+ reaching one is the normal case; present it as-is rather than treating it as a failure of
52
+ this command. A daemon that is simply not running is not one of these — it reports
53
+ `reachable false` and *passes*, because an on-demand daemon idle-exits by design.
54
+
55
+ ## 3. Present the report
56
+
57
+ End your output with the command's stdout **verbatim** in a fenced code block —
58
+ ` ```json ` for the JSON format, plain ` ``` ` for the human-readable one — so the user
59
+ can copy it out in one piece. Add nothing inside the block and do not summarize away
60
+ sections; the report is already redacted and complete.
61
+
62
+ ## 4. Debug a failing `log-errors`
63
+
64
+ When `log-errors` failed and the `/systematic-debugging` skill is available, invoke it to
65
+ drive root-cause investigation from the logs the check named. Otherwise read the last
66
+ error records yourself and reason from the failing step, code, msg, cause, and stack.
67
+
68
+ Read the report's `failures` first. Each group is one review's error records from both
69
+ logs with their codes (a session's, when the failure came before a review id existed), so
70
+ a hook-side record sits beside any daemon-side record from that review's own requests. A
71
+ daemon-wide failure (a crash, a bind failure, a failed update check) carries no id and
72
+ lands in `ungrouped`: read it alongside the group and correlate the two by `time`. Pull a
73
+ group's full records from both logs (`.sessionId` for a session group):
74
+
75
+ ```bash
76
+ dir="${XDG_STATE_HOME:-$HOME/.local/state}/caret"
77
+ grep -h '^{' "$dir/logs/caret.log" "$dir/logs/daemon.log" | jq -c 'select(.reviewId == "<id>")'
78
+ ```
79
+
80
+ For records outside any group or the report's window, fall back to the last error records
81
+ of each log:
82
+
83
+ ```bash
84
+ grep '^{' "$dir/logs/caret.log" | jq -s '[.[] | select(.level >= 50)] | .[-5:]'
85
+ grep '^{' "$dir/logs/daemon.log" | jq -s '[.[] | select(.level >= 50)] | .[-5:]'
86
+ tail -n 40 "$dir/logs/daemon-stderr.log"
87
+ ```
88
+
89
+ `log-errors` counts only NDJSON error records, so a crash that reached `daemon-stderr.log`
90
+ alone leaves it passing — tail that file even when the check is green. It fails only on
91
+ records from the last 24h, so a log that has settled passes while still reporting when it
92
+ last erred; work from that time rather than from the count. If a failure predates the
93
+ current live file, `gunzip -c` the segment you need from `logs/archive/` and rerun the
94
+ recipe against the result.
95
+
96
+ ## 5. Review this session's plans
97
+
98
+ The report counts reviews in aggregate; it does not say what happened in *this* session.
99
+ When the user wants that timeline, reconstruct it from the records — identify the session
100
+ by the most recently updated review whose `cwd` matches, then list every review in it,
101
+ oldest first:
102
+
103
+ ```bash
104
+ dir="${XDG_STATE_HOME:-$HOME/.local/state}/caret"
105
+ sid=$(jq -rs --arg cwd "$PWD" '[.[] | select(.cwd == $cwd)] | sort_by(.updatedAt) | last | .sessionId // empty' "$dir"/reviews/*.json)
106
+ jq -s --arg sid "$sid" '[.[] | select(.sessionId == $sid)] | sort_by(.createdAt) | .[] | {id, title, status, versions: (.versions | length), decidedAt: .decision.decidedAt, feedback: .decision.feedback}' "$dir"/reviews/*.json
107
+ ```
108
+
109
+ That field whitelist is deliberate: `versions[].plan` and `generalCommentDraft` hold full
110
+ plan and draft bodies — never select or echo them.
111
+
112
+ If `sid` comes back empty, no review matches the working directory. Say so, then fall back
113
+ to the most recently updated session across all reviews and re-run the listing with it:
114
+
115
+ ```bash
116
+ sid=$(jq -rs 'sort_by(.updatedAt) | last | .sessionId // empty' "$dir"/reviews/*.json)
117
+ ```
118
+
119
+ If `$dir/reviews` is missing or empty the glob won't match and these commands error (shell
120
+ or jq, depending on the shell) — that is "no reviews recorded", not a failure.
121
+
122
+ Present the result grouped by status, each review with its id, title, and version count
123
+ (the number of plan revisions):
124
+
125
+ - **pending** — awaiting a decision in the browser.
126
+ - **rejected** — changes requested; awaiting a revised plan. Include a short excerpt of
127
+ the decision `feedback`.
128
+ - **approved** — plan accepted; terminal success.
129
+ - **expired** — abandoned by its hook (timeout) or superseded by a resubmitted plan;
130
+ terminal, never reviewed.
131
+
132
+ ## 6. Sharing the raw logs
133
+
134
+ If the report is not enough and the user wants to hand the raw material to a maintainer,
135
+ `caret doctor --bundle` writes a zip of the live logs and review records to caret's state
136
+ dir. Tell them plainly before suggesting it: that archive is **not** redacted — it holds
137
+ their logs and full plan bodies — so it is written only after they confirm, and it should
138
+ move over a channel they trust. caret asks at a terminal and your run has none, so carry
139
+ their answer with `--yes` — never before they have given it.
@@ -0,0 +1,25 @@
1
+ ---
2
+ description: Plan a change and route the plan through caret's review UI before implementing it
3
+ argument-hint: [what you want done]
4
+ ---
5
+
6
+ Plan this, then implement it once caret approves the plan:
7
+
8
+ $ARGUMENTS
9
+
10
+ If that is empty, plan whatever the user asked for earlier in this session.
11
+
12
+ Call `EnterPlanMode` first: `ExitPlanMode` is refused outside plan mode. Research what the
13
+ change needs — read the relevant code, trace the real flow — then write the plan to the
14
+ file your plan-mode instructions name. Call `ExitPlanMode` with that same text as its
15
+ `plan` argument — caret reviews the argument, so a call without it reaches the review UI
16
+ empty.
17
+
18
+ This triggers caret's `PermissionRequest`/`ExitPlanMode` hook, which opens the plan in a
19
+ local browser UI for inline review. When the user approves or requests changes there, the
20
+ decision flows back to you:
21
+
22
+ - **Approved** → implement the plan.
23
+ - **Changes requested** → the feedback arrives as the denial reason. Re-read the plan file
24
+ (caret rewrites it in its canonical shape, so the feedback's line numbers match it),
25
+ revise it, and call `ExitPlanMode` again with the revised text as its `plan` argument.