carrick 0.3.82 → 0.3.83

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 (73) hide show
  1. package/README.md +46 -19
  2. package/bin/carrick.mjs +45 -2
  3. package/dist/contract.d.ts +17 -0
  4. package/dist/contract.js.map +1 -1
  5. package/dist/hook/apply-patch.d.ts +13 -0
  6. package/dist/hook/apply-patch.js +100 -0
  7. package/dist/hook/apply-patch.js.map +1 -0
  8. package/dist/hook/post-edit.d.ts +30 -1
  9. package/dist/hook/post-edit.js +95 -24
  10. package/dist/hook/post-edit.js.map +1 -1
  11. package/dist/hook/reuse.d.ts +97 -0
  12. package/dist/hook/reuse.js +245 -0
  13. package/dist/hook/reuse.js.map +1 -0
  14. package/dist/hook/stop.d.ts +3 -0
  15. package/dist/hook/stop.js +76 -0
  16. package/dist/hook/stop.js.map +1 -0
  17. package/dist/hook/user-prompt.d.ts +9 -0
  18. package/dist/hook/user-prompt.js +79 -0
  19. package/dist/hook/user-prompt.js.map +1 -0
  20. package/dist/init/codex.d.ts +51 -0
  21. package/dist/init/codex.js +167 -0
  22. package/dist/init/codex.js.map +1 -0
  23. package/dist/init/connect.d.ts +13 -0
  24. package/dist/init/connect.js +21 -15
  25. package/dist/init/connect.js.map +1 -1
  26. package/dist/init/doctor.d.ts +36 -0
  27. package/dist/init/doctor.js +97 -2
  28. package/dist/init/doctor.js.map +1 -1
  29. package/dist/init/files.d.ts +15 -0
  30. package/dist/init/files.js +20 -1
  31. package/dist/init/files.js.map +1 -1
  32. package/dist/init/outdated.d.ts +54 -0
  33. package/dist/init/outdated.js +175 -0
  34. package/dist/init/outdated.js.map +1 -0
  35. package/dist/init/output.d.ts +35 -3
  36. package/dist/init/output.js +115 -23
  37. package/dist/init/output.js.map +1 -1
  38. package/dist/init/projects.d.ts +27 -13
  39. package/dist/init/projects.js +48 -50
  40. package/dist/init/projects.js.map +1 -1
  41. package/dist/init/remove.d.ts +0 -2
  42. package/dist/init/remove.js +61 -15
  43. package/dist/init/remove.js.map +1 -1
  44. package/dist/init/repos.d.ts +34 -0
  45. package/dist/init/repos.js +77 -0
  46. package/dist/init/repos.js.map +1 -1
  47. package/dist/init/run.d.ts +73 -6
  48. package/dist/init/run.js +357 -94
  49. package/dist/init/run.js.map +1 -1
  50. package/dist/init/settings.d.ts +20 -0
  51. package/dist/init/settings.js +42 -4
  52. package/dist/init/settings.js.map +1 -1
  53. package/dist/init/task-skills.d.ts +27 -0
  54. package/dist/init/task-skills.js +64 -1
  55. package/dist/init/task-skills.js.map +1 -1
  56. package/dist/init/workspace-file.d.ts +73 -0
  57. package/dist/init/workspace-file.js +173 -0
  58. package/dist/init/workspace-file.js.map +1 -0
  59. package/package.json +6 -6
  60. package/plugin/hooks/hooks.json +11 -0
  61. package/sidecar/dist/src/capture/check-classify.d.ts +10 -1
  62. package/sidecar/dist/src/capture/check-classify.js +66 -8
  63. package/sidecar/dist/src/capture/check-deep.d.ts +16 -4
  64. package/sidecar/dist/src/capture/check-deep.js +21 -17
  65. package/sidecar/dist/src/capture/check-fields.d.ts +83 -0
  66. package/sidecar/dist/src/capture/check-fields.js +259 -0
  67. package/sidecar/dist/src/capture/check-probe.d.ts +21 -1
  68. package/sidecar/dist/src/capture/check-probe.js +39 -0
  69. package/sidecar/dist/src/capture/check.js +9 -2
  70. package/templates/skills/carrick-census.md +18 -9
  71. package/templates/skills/carrick-drift.md +7 -1
  72. package/templates/skills/carrick-impact.md +3 -1
  73. package/templates/skills/carrick-reuse.md +43 -26
package/README.md CHANGED
@@ -25,30 +25,51 @@ the hooks deliver, the CI check and a `carrick.json` written by hand, is in the
25
25
  agent's shell, a pipe — the same lines are written as plain text, with no colour
26
26
  and no spinner.
27
27
 
28
- Existing users can initialise the local workspace against a named Carrick
29
- project:
28
+ `init` runs in this order, and nothing is written — on this machine or in
29
+ Carrick — until you accept what it proposes:
30
+
31
+ 1. **The repos this install covers.** In a folder of sibling repos it asks
32
+ which ones, with every repo chosen to begin with. A folder routinely holds a
33
+ repo that should not be indexed, and a repo you leave out gets no proposal
34
+ entry, no project assignment and no connection. Without a terminal, name
35
+ them: `--repo owner/repo`, repeated or comma-separated. A folder of repos
36
+ with neither a terminal nor `--repo` stops there, having written nothing;
37
+ add `--yes` to cover all of them. A single repository is not a choice and is
38
+ never asked about.
39
+ 2. **The project.** Which project the selected repos belong in.
40
+ 3. **The proposal**, which names the packages found, the repos covered, any
41
+ project to create, and any repo that would move out of the project it is in
42
+ now. Answering no, or ending any question with Ctrl-C, ends the run with
43
+ nothing written.
44
+
45
+ Existing users can name the project on the command line:
30
46
 
31
47
  ```
32
- carrick init --project payments
48
+ carrick init --project payments --allow-move
33
49
  ```
34
50
 
35
- The command shows the current project assignment for every proposed GitHub
36
- repo. When the project is not in the workspace yet, it lists the workspace's
37
- projects and offers to create the named one from the terminal; where the API
38
- has no such action it prints the project link instead. Connected repos are then
39
- put in the project from the terminal too, so the GitHub App grant is the only
40
- browser step; where the API has no assignment action, the command prints the
41
- repo-assignment link and, in an interactive terminal, opens the page. Either
42
- way the claim comes from a read. The CLI reads `resolve-repos` until every
43
- proposed repo reports `project_slug: "payments"`, and a repo connected to
51
+ `--project` puts the selected repos in that project, creating it from the
52
+ terminal where the API allows that and printing the project link where it does
53
+ not. A repo that is already in another project is **moved** out of it, which
54
+ changes what every agent querying either project can see, so the move is named
55
+ in the proposal with the project it comes out of and asked about separately.
56
+ `--yes` does not grant it: `--allow-move` does, and without either the run
57
+ stops before anything is moved.
58
+
59
+ Connected repos are placed from the terminal, so the GitHub App grant is the
60
+ only browser step; where the API has no assignment action, the command prints
61
+ the repo-assignment link and, in an interactive terminal, opens the page.
62
+ Either way the claim comes from a read. The CLI reads `resolve-repos` until
63
+ every covered repo reports `project_slug: "payments"`, and a repo connected to
44
64
  another project remains pending. A target it cannot meet does not stop the run.
45
65
  The hooks, the MCP connection and the proposal are written, and the command
46
66
  says which browser steps are left.
47
67
 
48
68
  Without `--project` the project step still runs: the command takes the project
49
69
  the repos are already in, and otherwise lists the workspace's projects for you
50
- to name one, which it creates from the terminal where the API allows that. An
51
- empty answer leaves the step to the browser.
70
+ to name one. An empty answer leaves the step to the browser. Every project is
71
+ printed as the dashboard shows it, display name and slug both — `Payments
72
+ (payments)`.
52
73
 
53
74
  Each repository is identified by its `origin` remote. A remote written through
54
75
  a per-account SSH host alias (`git@github.com-work:owner/repo.git`) is resolved
@@ -56,7 +77,8 @@ with `ssh -G`, so an alias whose `HostName` is `github.com` is an ordinary
56
77
  GitHub repository here. When a repository still names none, `init` says which
57
78
  one it was and what it read, and leaves that repository out of the project and
58
79
  connection steps rather than dropping it quietly. `carrick init --repo
59
- owner/repo` names the repository in that case.
80
+ owner/repo` names the repository in that case: a `--repo` value that matches no
81
+ repo in the folder attaches to the one repo there that has no identity.
60
82
 
61
83
  Credentials live in `$XDG_CONFIG_HOME/carrick/credentials.json`, falling back
62
84
  to `~/.config/carrick/` on macOS and Linux or `%APPDATA%\carrick\` on Windows.
@@ -79,9 +101,14 @@ exists. It is the only scan a first run makes.
79
101
 
80
102
  Workspace detection handles a repo root or immediate sibling repositories.
81
103
  An optional `carrick-workspace.json` adds paths through `repos` and removes
82
- directory names through `exclude`; init preserves this file and does not
83
- create one. `carrick derive --workspace . --json` previews the Rust proposal
84
- without writing files or scanning.
104
+ directory names through `exclude`. Where you leave a repo out of the selection,
105
+ init writes that name into `exclude` and records it under a `carrick` key
106
+ beside it: every later command reads the same answer, so the scans, the editor
107
+ hooks and the next `init` all leave that repo alone, and `carrick remove` takes
108
+ back the names init added and nothing you wrote yourself. `--repo` naming an
109
+ excluded repo is refused and says which file excludes it. `carrick derive
110
+ --workspace . --json` previews the Rust proposal without writing files or
111
+ scanning.
85
112
 
86
113
  Deno projects use their existing `deno.json` or `deno.jsonc` and require Deno
87
114
  2.9.4 or newer on PATH. Before local indexing, prepare their dependencies with
@@ -114,7 +141,7 @@ types in a Node process.
114
141
  |---|---|
115
142
  | `carrick login` | Authorise a Carrick workspace in the browser, or verify `CARRICK_TOKEN` |
116
143
  | `carrick logout` | Remove the saved local credential |
117
- | `carrick init [--project SLUG] [--repo OWNER/REPO]` | The repo list, the project, the service proposal in `.carrick/`, the agent hooks, the MCP connection, and the prompt that writes `carrick.json` |
144
+ | `carrick init [--repo OWNER/REPO]... [--project SLUG] [--allow-move]` | The repos this install covers, the project, the service proposal in `.carrick/`, the agent hooks, the MCP connection, and the prompt that writes `carrick.json` |
118
145
  | `carrick doctor` | Re-check that setup: the declared paths, the CI workflow against the current template, the hooks, the MCP connection and how far the index is behind |
119
146
  | `carrick remove [--keep-login]` | Undo all of that on this machine, and list the files the scaffold added to the repository |
120
147
  | `carrick index` | Derive the workspace, apply optional repo overrides and write `.carrick/`, with Carrick classifying what the deterministic passes could not |
package/bin/carrick.mjs CHANGED
@@ -38,11 +38,50 @@ if (nodeMajor() < NODE_FLOOR) {
38
38
  const HOOKS = {
39
39
  "post-edit": "../dist/hook/post-edit.js",
40
40
  "session-start": "../dist/hook/session-start.js",
41
+ stop: "../dist/hook/stop.js",
42
+ "user-prompt": "../dist/hook/user-prompt.js",
41
43
  };
42
44
 
43
45
  const argv = process.argv.slice(2);
44
46
  const [command, ...rest] = argv;
45
47
 
48
+ /**
49
+ * The commands that say nothing about the state of the install (carrick#1333).
50
+ *
51
+ * `hook` and `lsp` are protocol channels — a line of prose on either is a line
52
+ * an agent reads as data — and `init`, `doctor` and `remove` are the commands
53
+ * that write, audit and undo the very files the notice would be about, so each
54
+ * of them says it better in its own words.
55
+ */
56
+ const NO_NOTICE = new Set(["hook", "lsp", "init", "doctor", "remove"]);
57
+
58
+ /**
59
+ * One line a day, on stderr, naming what an upgrade left behind here.
60
+ *
61
+ * `npm install -g carrick@latest` changes the binary and nothing else, so a
62
+ * repo keeps the hook entries and skill bodies of whichever version first ran
63
+ * `carrick init` in it. Nothing re-reads them, and nobody is told.
64
+ *
65
+ * It runs before the command, never instead of it, and cannot fail one: a
66
+ * throw, a workspace Carrick was never set up in, or an install that is
67
+ * current all leave it silent.
68
+ */
69
+ async function refreshNoticeLine() {
70
+ if (command === undefined || NO_NOTICE.has(command)) return;
71
+ try {
72
+ const { initialisedRoot, refreshNotice } = await import("../dist/init/outdated.js");
73
+ const root = initialisedRoot(process.cwd());
74
+ if (root === null) return;
75
+ const line = refreshNotice(root);
76
+ if (line) process.stderr.write(`carrick: ${line}\n`);
77
+ } catch {
78
+ // A notice about the install must never be the reason a command did not
79
+ // run.
80
+ }
81
+ }
82
+
83
+ await refreshNoticeLine();
84
+
46
85
  /**
47
86
  * Run a build of the index and render it (carrick#1315).
48
87
  *
@@ -162,9 +201,13 @@ function extraHelp() {
162
201
  "INTEGRATION:",
163
202
  " lsp --stdio the language server, for an editor or an agent",
164
203
  " that speaks LSP",
165
- " hook post-edit Claude Code PostToolUse hook (reads the tool",
166
- " payload on stdin)",
204
+ " hook post-edit PostToolUse hook for either host (reads the",
205
+ " tool payload on stdin)",
167
206
  " hook session-start Claude Code SessionStart hook",
207
+ " hook stop Claude Code Stop hook (one reuse nudge per",
208
+ " task, silent when the task added no function)",
209
+ " hook user-prompt Codex UserPromptSubmit hook (the same nudge,",
210
+ " delivered on the next prompt)",
168
211
  " templates <name> print a file to add to a repo: workflow, or",
169
212
  " carrick.json",
170
213
  " --version the version of this package",
@@ -144,6 +144,23 @@ export type Recheck = {
144
144
  stale_since?: string;
145
145
  /** Why the re-check did not run. Only on a `none`. */
146
146
  reason?: string;
147
+ /**
148
+ * Functions the re-extracted file declares that the index does not hold
149
+ * under that name (carrick#1330). Absent on a `none`, which extracted
150
+ * nothing to compare, and absent when the edit added no function.
151
+ *
152
+ * A name comparison against `index_commit`, and both halves matter: the
153
+ * index holds no body hash, so a renamed function reads as new, and the
154
+ * commit is the one the last scan of that repo ran on.
155
+ */
156
+ new_functions?: NewFunction[];
157
+ };
158
+ /** One function the working tree declares and the index does not. */
159
+ export type NewFunction = {
160
+ /** As the source spells it: `name`, or `Class.member`. */
161
+ name: string;
162
+ /** Where it starts, so a reader can open it without searching. */
163
+ line: number;
147
164
  };
148
165
  export declare const SCHEMA = "carrick.check/0";
149
166
  export declare const STATUS_SCHEMA = "carrick.status/0";
@@ -1 +1 @@
1
- {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,EAAE;AACF,yDAAyD;AACzD,+EAA+E;AAC/E,4DAA4D;AAC5D,6EAA6E;AAC7E,6EAA6E;AAC7E,+EAA+E;AAC/E,0CAA0C;AAiL1C,MAAM,CAAC,MAAM,MAAM,GAAG,iBAAiB,CAAC;AACxC,MAAM,CAAC,MAAM,aAAa,GAAG,kBAAkB,CAAC;AA4KhD,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACtD,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IAC7C,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAE,MAAM,CAAC,OAAO,CAAiB,CAAC,CAAC,CAAC,EAAE,CAAC;IACrF,MAAM,MAAM,GAAgB;QAC1B,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC;QACxB,KAAK;KACN,CAAC;IACF,IAAI,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,QAAQ;QAAE,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IACxE,IAAI,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,QAAQ;QAAE,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IAC9E,IAAI,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,QAAQ;QAAE,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IACrE,IAAI,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,QAAQ;QAAE,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IACrE,IAAI,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,QAAQ;QAAE,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IAC9E,IAAI,OAAO,MAAM,CAAC,cAAc,CAAC,KAAK,QAAQ;QAAE,MAAM,CAAC,YAAY,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;IAC7F,IAAI,OAAO,MAAM,CAAC,YAAY,CAAC,KAAK,QAAQ;QAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IACvF,IAAI,OAAO,MAAM,CAAC,iBAAiB,CAAC,KAAK,QAAQ,EAAE,CAAC;QAClD,MAAM,CAAC,eAAe,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;IACrD,CAAC;IACD,IAAI,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,SAAS;QAAE,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IAC/E,IAAI,OAAO,MAAM,CAAC,qBAAqB,CAAC,KAAK,QAAQ,EAAE,CAAC;QACtD,MAAM,CAAC,mBAAmB,GAAG,MAAM,CAAC,qBAAqB,CAAC,CAAC;IAC7D,CAAC;IACD,IAAI,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,SAAS;QAAE,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IACzE,IAAI,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAAE,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAa,CAAC;IACnF,IAAI,OAAO,MAAM,CAAC,eAAe,CAAC,KAAK,QAAQ;QAAE,MAAM,CAAC,aAAa,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;IAChG,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC;QAC5C,MAAM,KAAK,GAAI,MAAM,CAAC,gBAAgB,CAAe,CAAC,MAAM,CAC1D,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CACnD,CAAC;QACF,IAAI,KAAK,CAAC,MAAM;YAAE,MAAM,CAAC,cAAc,GAAG,KAAK,CAAC;IAClD,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IAClC,IAAI,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,OAAO,CAAC,KAAK,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC5D,MAAM,CAAC,OAAO,GAAG,OAA6B,CAAC;IACjD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,aAAa;QAAE,OAAO,IAAI,CAAC;IACpD,MAAM,MAAM,GAAiB,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IACrE,IAAI,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,QAAQ;QAAE,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IACxE,IAAI,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,QAAQ;QAAE,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IAC9E,IAAI,OAAO,MAAM,CAAC,WAAW,CAAC,KAAK,QAAQ;QAAE,MAAM,CAAC,SAAS,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;IACpF,IAAI,OAAO,MAAM,CAAC,YAAY,CAAC,KAAK,QAAQ;QAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;IACvF,IAAI,OAAO,MAAM,CAAC,iBAAiB,CAAC,KAAK,QAAQ,EAAE,CAAC;QAClD,MAAM,CAAC,eAAe,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;IACrD,CAAC;IACD,IAAI,OAAO,MAAM,CAAC,mBAAmB,CAAC,KAAK,QAAQ,EAAE,CAAC;QACpD,MAAM,CAAC,iBAAiB,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC;IACzD,CAAC;IACD,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7E,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QAC7B,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,SAAS;QAC/B,IAAI,OAAO,KAAK,CAAC,SAAS,CAAC,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,QAAQ;YAAE,SAAS;QACxF,IAAI,OAAO,KAAK,CAAC,cAAc,CAAC,KAAK,QAAQ;YAAE,SAAS;QACxD,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAiC,CAAC,CAAC;IAC1D,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACpF,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,SAAS;QAC/B,IAAI,OAAO,KAAK,CAAC,SAAS,CAAC,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,QAAQ,CAAC,KAAK,QAAQ;YAAE,SAAS;QAC1F,CAAC,MAAM,CAAC,aAAa,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,KAA+B,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAChF,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI;YAAE,CAAC,MAAM,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7E,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;IACrC,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;QAC3D,MAAM,CAAC,SAAS,GAAG,QAA+B,CAAC;IACrD,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACpE,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,SAAS;QAC/B,IAAI,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,QAAQ;YAAE,SAAS;QACrF,IAAI,OAAO,KAAK,CAAC,uBAAuB,CAAC,KAAK,QAAQ;YAAE,SAAS;QACjE,CAAC,MAAM,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,KAA8B,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,WAAW,CAAC,IAAe;IACzC,OAAO,IAAI,CAAC,MAAM,KAAK,WAAW,CAAC;AACrC,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,YAAY,CAAC,MAAmB;IAC9C,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAC3B,OAAO,OAAO,CAAC,MAAM,IAAI,IAAI,IAAI,OAAO,CAAC,MAAM,KAAK,YAAY,CAAC;IACnE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,cAAc,CAAC,MAAmB;IAChD,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACrF,CAAC"}
@@ -0,0 +1,13 @@
1
+ /** Whether a string is an `apply_patch` envelope at all. */
2
+ export declare function looksLikePatch(text: string): boolean;
3
+ /**
4
+ * The paths a patch leaves on disk, in the order it names them.
5
+ *
6
+ * Relative to the cwd the tool ran in, exactly as the patch spells them, and
7
+ * deduplicated: a caller turns them into workspace-relative paths because only
8
+ * it knows the root.
9
+ *
10
+ * Anything that is not a patch gives an empty list, so a caller can hand this
11
+ * whatever a `command` field held without asking first.
12
+ */
13
+ export declare function patchedFiles(text: string): string[];
@@ -0,0 +1,100 @@
1
+ // The files one `apply_patch` call leaves on disk (carrick#1335).
2
+ //
3
+ // Codex has no `Edit`/`Write` tool with a `file_path`. It edits through
4
+ // `apply_patch`, whose PostToolUse payload is
5
+ // `tool_input: { "command": "<the patch text>" }`
6
+ // (`codex-rs/core/src/tools/handlers/apply_patch.rs`), and one patch can add,
7
+ // update, delete and rename several files at once. So the recording half of
8
+ // the reuse nudge needs this: the patch text in, the paths worth re-checking
9
+ // out.
10
+ //
11
+ // The grammar is four header lines, each at the start of its own line, inside
12
+ // a `*** Begin Patch` / `*** End Patch` envelope (`codex-rs/apply-patch`):
13
+ //
14
+ // *** Add File: <path>
15
+ // *** Update File: <path>
16
+ // *** Delete File: <path>
17
+ // *** Move to: <path> (only ever after an Update File)
18
+ //
19
+ // Body lines carry a `+`, `-` or space prefix, so a line beginning `*** ` is a
20
+ // header and nothing else. `*** End of File` is a marker, not a path, and is
21
+ // ignored with everything else that is not one of the four.
22
+ //
23
+ // Two of the four are not simply "a file that changed":
24
+ //
25
+ // * `Delete File` names a path that is GONE once the patch applies. Re-checking
26
+ // it asks the CLI about a file that is not there, so it is dropped here
27
+ // rather than filtered later.
28
+ // * `Move to` renames the `Update File` above it. The file the index should be
29
+ // compared against is the destination, so the destination replaces the source
30
+ // rather than joining it.
31
+ //
32
+ // Reference: `docs/reference/task-skills.md`, "The reuse nudge".
33
+ /** The header that opens a patch, used to tell a patch from any other string. */
34
+ const ENVELOPE = "*** Begin Patch";
35
+ const HEADERS = [
36
+ { marker: "*** Add File: ", kind: "add" },
37
+ { marker: "*** Update File: ", kind: "update" },
38
+ { marker: "*** Delete File: ", kind: "delete" },
39
+ { marker: "*** Move to: ", kind: "move" },
40
+ ];
41
+ function header(line) {
42
+ for (const candidate of HEADERS) {
43
+ if (line.startsWith(candidate.marker)) {
44
+ const path = line.slice(candidate.marker.length).trim();
45
+ if (path !== "")
46
+ return { kind: candidate.kind, path };
47
+ }
48
+ }
49
+ return null;
50
+ }
51
+ /** Whether a string is an `apply_patch` envelope at all. */
52
+ export function looksLikePatch(text) {
53
+ return text.includes(ENVELOPE);
54
+ }
55
+ /**
56
+ * The paths a patch leaves on disk, in the order it names them.
57
+ *
58
+ * Relative to the cwd the tool ran in, exactly as the patch spells them, and
59
+ * deduplicated: a caller turns them into workspace-relative paths because only
60
+ * it knows the root.
61
+ *
62
+ * Anything that is not a patch gives an empty list, so a caller can hand this
63
+ * whatever a `command` field held without asking first.
64
+ */
65
+ export function patchedFiles(text) {
66
+ if (!looksLikePatch(text))
67
+ return [];
68
+ const files = [];
69
+ // Where the last `Update File` put its path, so a `Move to` under it replaces
70
+ // that entry instead of adding a second one for a file that no longer exists.
71
+ let lastUpdate = null;
72
+ for (const line of text.split("\n")) {
73
+ const found = header(line.trimEnd());
74
+ if (found === null)
75
+ continue;
76
+ switch (found.kind) {
77
+ case "delete":
78
+ lastUpdate = null;
79
+ break;
80
+ case "move":
81
+ if (lastUpdate === null) {
82
+ files.push(found.path);
83
+ }
84
+ else {
85
+ files[lastUpdate] = found.path;
86
+ }
87
+ lastUpdate = null;
88
+ break;
89
+ case "update":
90
+ lastUpdate = files.push(found.path) - 1;
91
+ break;
92
+ case "add":
93
+ files.push(found.path);
94
+ lastUpdate = null;
95
+ break;
96
+ }
97
+ }
98
+ return [...new Set(files)];
99
+ }
100
+ //# sourceMappingURL=apply-patch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply-patch.js","sourceRoot":"","sources":["../../src/hook/apply-patch.ts"],"names":[],"mappings":"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"}
@@ -1,13 +1,42 @@
1
1
  #!/usr/bin/env node
2
+ import type { CheckResult } from "../contract.ts";
3
+ import type { NewFunction } from "./reuse.ts";
2
4
  type Payload = {
3
5
  cwd?: string;
6
+ session_id?: string;
4
7
  tool_input?: {
5
8
  file_path?: string;
6
9
  filePath?: string;
7
10
  edits?: Array<{
8
11
  file_path?: string;
9
12
  }>;
13
+ /** Codex's `apply_patch`: the patch text itself. */
14
+ command?: unknown;
10
15
  };
11
16
  };
12
- export declare function fileFromPayload(payload: Payload): string | null;
17
+ /**
18
+ * What the re-check said this file declares and the index does not
19
+ * (carrick#1330).
20
+ *
21
+ * Nothing is printed about it here. This hook fires on every edit and most
22
+ * edits add no function; the one line about the ones that did belongs at the
23
+ * end of the task, where it costs one model turn instead of one per edit. All
24
+ * this does is put the names somewhere the Stop hook can find them.
25
+ */
26
+ export declare function newFunctions(result: CheckResult, file: string): NewFunction[];
27
+ /**
28
+ * Every file one tool call left on disk, whichever host made it.
29
+ *
30
+ * A named file wins where there is one: that is Claude Code, and its path is
31
+ * absolute. Otherwise the `command` field is read as a patch, which is Codex's
32
+ * `apply_patch` — its paths are relative to the cwd the tool ran in, and a
33
+ * string that is not a patch gives nothing, so nothing here has to ask which
34
+ * host is calling.
35
+ *
36
+ * A shell command that is not a patch reaches the same branch and yields an
37
+ * empty list, which is why this does not test `tool_name`: the patch text
38
+ * recognises itself, and an `apply_patch` run through a shell is recorded on
39
+ * the same terms as one run as a tool.
40
+ */
41
+ export declare function filesFromPayload(payload: Payload): string[];
13
42
  export {};
@@ -1,10 +1,16 @@
1
1
  #!/usr/bin/env node
2
- // PostToolUse hook for Edit, Write and MultiEdit.
2
+ // PostToolUse hook for a file edit, on either host.
3
3
  //
4
4
  // Reads the tool payload on stdin, runs `carrick check <file> --json` from the
5
- // workspace root and prints the verdicts as `additionalContext`, which Claude
6
- // Code attaches to the tool result. Attaching to the result rather than to the
7
- // next turn is why this channel has no "the run ended on the edit" hole.
5
+ // workspace root and prints the verdicts as `additionalContext`, which the host
6
+ // attaches to the tool result. Attaching to the result rather than to the next
7
+ // turn is why this channel has no "the run ended on the edit" hole.
8
+ //
9
+ // Two payload shapes reach it, because the two hosts edit differently
10
+ // (carrick#1335). Claude Code's `Edit`, `Write` and `MultiEdit` name one file
11
+ // in `tool_input.file_path`. Codex's `apply_patch` carries a patch in
12
+ // `tool_input.command`, and one patch can touch several files — so the file is
13
+ // a list here, checked in the order the payload names them.
8
14
  //
9
15
  // It exits 0 whatever happens. An edit never fails because Carrick had nothing
10
16
  // to say, could not find its binary, or timed out.
@@ -14,12 +20,47 @@ import { resolveChannel } from "../channel.js";
14
20
  import { createLogger } from "../log.js";
15
21
  import { renderPostToolUse } from "../render.js";
16
22
  import { resolveRoot, rootNote } from "../root.js";
23
+ import { patchedFiles } from "./apply-patch.js";
24
+ import { record } from "./reuse.js";
17
25
  const log = createLogger("carrick-hook");
18
26
  /** The files the index has rows for. */
19
27
  const CHECKED = /\.(ts|tsx|mts|cts)$/;
20
- export function fileFromPayload(payload) {
28
+ /**
29
+ * What the re-check said this file declares and the index does not
30
+ * (carrick#1330).
31
+ *
32
+ * Nothing is printed about it here. This hook fires on every edit and most
33
+ * edits add no function; the one line about the ones that did belongs at the
34
+ * end of the task, where it costs one model turn instead of one per edit. All
35
+ * this does is put the names somewhere the Stop hook can find them.
36
+ */
37
+ export function newFunctions(result, file) {
38
+ return (result.recheck?.new_functions ?? []).map((entry) => ({
39
+ name: entry.name,
40
+ file: result.file ?? file,
41
+ indexCommit: result.index_commit ?? "",
42
+ }));
43
+ }
44
+ /**
45
+ * Every file one tool call left on disk, whichever host made it.
46
+ *
47
+ * A named file wins where there is one: that is Claude Code, and its path is
48
+ * absolute. Otherwise the `command` field is read as a patch, which is Codex's
49
+ * `apply_patch` — its paths are relative to the cwd the tool ran in, and a
50
+ * string that is not a patch gives nothing, so nothing here has to ask which
51
+ * host is calling.
52
+ *
53
+ * A shell command that is not a patch reaches the same branch and yields an
54
+ * empty list, which is why this does not test `tool_name`: the patch text
55
+ * recognises itself, and an `apply_patch` run through a shell is recorded on
56
+ * the same terms as one run as a tool.
57
+ */
58
+ export function filesFromPayload(payload) {
21
59
  const input = payload.tool_input ?? {};
22
- return input.file_path ?? input.filePath ?? input.edits?.[0]?.file_path ?? null;
60
+ const named = input.file_path ?? input.filePath ?? input.edits?.[0]?.file_path ?? null;
61
+ if (named)
62
+ return [named];
63
+ return typeof input.command === "string" ? patchedFiles(input.command) : [];
23
64
  }
24
65
  function emit(context) {
25
66
  process.stdout.write(JSON.stringify({
@@ -36,9 +77,13 @@ async function readStdin() {
36
77
  return Buffer.concat(chunks).toString("utf8");
37
78
  }
38
79
  async function main() {
80
+ // `off` stops the work as well as the printing. `lsp` stops only the
81
+ // printing: it decides which surface delivers a verdict, and the reuse
82
+ // record below is not a verdict — it is what the Stop hook speaks from, and
83
+ // the language server has no equivalent of that moment (carrick#1330).
39
84
  const channel = resolveChannel({ hooksInstalled: true });
40
- if (channel.channel !== "hook") {
41
- log(`the ${channel.channel} channel owns delivery in this install; printing nothing`);
85
+ if (channel.channel === "off") {
86
+ log("CARRICK_CHANNEL=off; doing nothing");
42
87
  return;
43
88
  }
44
89
  let payload;
@@ -49,31 +94,57 @@ async function main() {
49
94
  log("unparseable payload", String(error));
50
95
  return;
51
96
  }
52
- const file = fileFromPayload(payload);
53
- if (!file || !CHECKED.test(file))
97
+ // A patch can name a file this index has no rows for beside one it does, so
98
+ // the filter is per file rather than a reason to drop the call.
99
+ const cwd = payload.cwd ?? null;
100
+ const edited = filesFromPayload(payload)
101
+ .filter((file) => CHECKED.test(file))
102
+ .map((file) => (path.isAbsolute(file) ? file : path.resolve(cwd ?? process.cwd(), file)));
103
+ if (edited.length === 0)
54
104
  return;
105
+ // One root for the call: every file in one patch is in the workspace the tool
106
+ // ran in, and resolving it per file would ask the same question repeatedly.
55
107
  const choice = resolveRoot({
56
- clientRoot: payload.cwd ?? null,
108
+ clientRoot: cwd,
57
109
  projectDir: process.env["CLAUDE_PROJECT_DIR"] ?? null,
58
- filePath: file,
110
+ filePath: edited[0],
59
111
  });
60
112
  const note = rootNote(choice);
61
113
  if (note)
62
114
  log(note);
63
- const relative = path.isAbsolute(file) ? path.relative(choice.root, file) : file;
64
- // The edit just landed, so the index describes the file as it was before it.
65
- // This is the one surface that asks for the file to be re-judged from the
66
- // working tree; it fires once per completed edit, where the language server
67
- // fires on every save (carrick#1036).
68
- const outcome = await check(relative, { cwd: choice.root, recheck: true });
69
- if (!outcome.result) {
70
- log("no answer for", relative, outcome.failure ?? "");
115
+ const found = [];
116
+ const contexts = [];
117
+ for (const file of edited) {
118
+ const relative = path.relative(choice.root, file);
119
+ // The edit just landed, so the index describes the file as it was before
120
+ // it. This is the one surface that asks for the file to be re-judged from
121
+ // the working tree; it fires once per completed edit, where the language
122
+ // server fires on every save (carrick#1036).
123
+ const outcome = await check(relative, { cwd: choice.root, recheck: true });
124
+ if (!outcome.result) {
125
+ // One unreadable file in a patch of four is not a reason to say nothing
126
+ // about the other three.
127
+ log("no answer for", relative, outcome.failure ?? "");
128
+ continue;
129
+ }
130
+ found.push(...newFunctions(outcome.result, relative));
131
+ const context = renderPostToolUse(outcome.result, relative);
132
+ log(`check ${relative} -> ${context ? "context" : "nothing to say"} in ${outcome.ms}ms`);
133
+ if (context)
134
+ contexts.push(context);
135
+ }
136
+ // Silent and local: the names go to a file under the user's home directory
137
+ // and nothing about them is printed here.
138
+ if (found.length > 0 && payload.session_id) {
139
+ record(payload.session_id, found);
140
+ log(`recorded ${found.length} new function(s) for ${payload.session_id}`);
141
+ }
142
+ if (channel.channel !== "hook") {
143
+ log(`the ${channel.channel} channel owns delivery in this install; printing nothing`);
71
144
  return;
72
145
  }
73
- const context = renderPostToolUse(outcome.result, relative);
74
- log(`check ${relative} -> ${context ? "context" : "nothing to say"} in ${outcome.ms}ms`);
75
- if (context)
76
- emit(context);
146
+ if (contexts.length > 0)
147
+ emit(contexts.join("\n\n"));
77
148
  }
78
149
  await main();
79
150
  process.exit(0);
@@ -1 +1 @@
1
- {"version":3,"file":"post-edit.js","sourceRoot":"","sources":["../../src/hook/post-edit.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"post-edit.js","sourceRoot":"","sources":["../../src/hook/post-edit.ts"],"names":[],"mappings":";AACA,oDAAoD;AACpD,EAAE;AACF,+EAA+E;AAC/E,gFAAgF;AAChF,+EAA+E;AAC/E,oEAAoE;AACpE,EAAE;AACF,sEAAsE;AACtE,8EAA8E;AAC9E,sEAAsE;AACtE,+EAA+E;AAC/E,4DAA4D;AAC5D,EAAE;AACF,+EAA+E;AAC/E,mDAAmD;AAEnD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAIpC,MAAM,GAAG,GAAG,YAAY,CAAC,cAAc,CAAC,CAAC;AACzC,wCAAwC;AACxC,MAAM,OAAO,GAAG,qBAAqB,CAAC;AActC;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,MAAmB,EAAE,IAAY;IAC5D,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,aAAa,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC3D,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,IAAI;QACzB,WAAW,EAAE,MAAM,CAAC,YAAY,IAAI,EAAE;KACvC,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAgB;IAC/C,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC;IACvC,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,IAAI,IAAI,CAAC;IACvF,IAAI,KAAK;QAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAC1B,OAAO,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC9E,CAAC;AAED,SAAS,IAAI,CAAC,OAAe;IAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,IAAI,CAAC,SAAS,CAAC;QACb,kBAAkB,EAAE;YAClB,aAAa,EAAE,aAAa;YAC5B,iBAAiB,EAAE,OAAO;SAC3B;KACF,CAAC,CACH,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,SAAS;IACtB,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK;QAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IACzE,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAChD,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,qEAAqE;IACrE,uEAAuE;IACvE,4EAA4E;IAC5E,uEAAuE;IACvE,MAAM,OAAO,GAAG,cAAc,CAAC,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,IAAI,OAAO,CAAC,OAAO,KAAK,KAAK,EAAE,CAAC;QAC9B,GAAG,CAAC,oCAAoC,CAAC,CAAC;QAC1C,OAAO;IACT,CAAC;IAED,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,SAAS,EAAE,CAAC,IAAI,IAAI,CAAY,CAAC;IAC/D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,qBAAqB,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC1C,OAAO;IACT,CAAC;IAED,4EAA4E;IAC5E,gEAAgE;IAChE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC;IAChC,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,CAAC;SACrC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;SACpC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5F,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAEhC,8EAA8E;IAC9E,4EAA4E;IAC5E,MAAM,MAAM,GAAG,WAAW,CAAC;QACzB,UAAU,EAAE,GAAG;QACf,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,IAAI;QACrD,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAE;KACrB,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9B,IAAI,IAAI;QAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IAEpB,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;QAC1B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAClD,yEAAyE;QACzE,0EAA0E;QAC1E,yEAAyE;QACzE,6CAA6C;QAC7C,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3E,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACpB,wEAAwE;YACxE,yBAAyB;YACzB,GAAG,CAAC,eAAe,EAAE,QAAQ,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;YACtD,SAAS;QACX,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;QACtD,MAAM,OAAO,GAAG,iBAAiB,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC5D,GAAG,CAAC,SAAS,QAAQ,OAAO,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,gBAAgB,OAAO,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;QACzF,IAAI,OAAO;YAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;IAED,2EAA2E;IAC3E,0CAA0C;IAC1C,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QAC3C,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAClC,GAAG,CAAC,YAAY,KAAK,CAAC,MAAM,wBAAwB,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IAC5E,CAAC;IAED,IAAI,OAAO,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;QAC/B,GAAG,CAAC,OAAO,OAAO,CAAC,OAAO,0DAA0D,CAAC,CAAC;QACtF,OAAO;IACT,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,IAAI,EAAE,CAAC;AACb,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC"}