grounder 0.0.1 → 0.0.2

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 (135) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +169 -2
  3. package/dist/agents/claude.d.ts +7 -0
  4. package/dist/agents/claude.d.ts.map +1 -0
  5. package/dist/agents/claude.js +46 -0
  6. package/dist/agents/claude.js.map +1 -0
  7. package/dist/agents/cursor.d.ts +7 -0
  8. package/dist/agents/cursor.d.ts.map +1 -0
  9. package/dist/agents/cursor.js +46 -0
  10. package/dist/agents/cursor.js.map +1 -0
  11. package/dist/agents/index.d.ts +11 -0
  12. package/dist/agents/index.d.ts.map +1 -0
  13. package/dist/agents/index.js +23 -0
  14. package/dist/agents/index.js.map +1 -0
  15. package/dist/agents/types.d.ts +20 -0
  16. package/dist/agents/types.d.ts.map +1 -0
  17. package/dist/agents/types.js +2 -0
  18. package/dist/agents/types.js.map +1 -0
  19. package/dist/cli.d.ts +3 -0
  20. package/dist/cli.d.ts.map +1 -0
  21. package/dist/cli.js +95 -0
  22. package/dist/cli.js.map +1 -0
  23. package/dist/commands/handoff/list.d.ts +23 -0
  24. package/dist/commands/handoff/list.d.ts.map +1 -0
  25. package/dist/commands/handoff/list.js +64 -0
  26. package/dist/commands/handoff/list.js.map +1 -0
  27. package/dist/commands/handoff.d.ts +25 -0
  28. package/dist/commands/handoff.d.ts.map +1 -0
  29. package/dist/commands/handoff.js +47 -0
  30. package/dist/commands/handoff.js.map +1 -0
  31. package/dist/commands/note.d.ts +10 -0
  32. package/dist/commands/note.d.ts.map +1 -0
  33. package/dist/commands/note.js +33 -0
  34. package/dist/commands/note.js.map +1 -0
  35. package/dist/commands/path/logs.d.ts +7 -0
  36. package/dist/commands/path/logs.d.ts.map +1 -0
  37. package/dist/commands/path/logs.js +17 -0
  38. package/dist/commands/path/logs.js.map +1 -0
  39. package/dist/commands/path/notes.d.ts +7 -0
  40. package/dist/commands/path/notes.d.ts.map +1 -0
  41. package/dist/commands/path/notes.js +17 -0
  42. package/dist/commands/path/notes.js.map +1 -0
  43. package/dist/commands/repo/init.d.ts +11 -0
  44. package/dist/commands/repo/init.d.ts.map +1 -0
  45. package/dist/commands/repo/init.js +78 -0
  46. package/dist/commands/repo/init.js.map +1 -0
  47. package/dist/commands/require-linked.d.ts +7 -0
  48. package/dist/commands/require-linked.d.ts.map +1 -0
  49. package/dist/commands/require-linked.js +19 -0
  50. package/dist/commands/require-linked.js.map +1 -0
  51. package/dist/commands/vault/init.d.ts +11 -0
  52. package/dist/commands/vault/init.d.ts.map +1 -0
  53. package/dist/commands/vault/init.js +73 -0
  54. package/dist/commands/vault/init.js.map +1 -0
  55. package/dist/connector/git.d.ts +12 -0
  56. package/dist/connector/git.d.ts.map +1 -0
  57. package/dist/connector/git.js +53 -0
  58. package/dist/connector/git.js.map +1 -0
  59. package/dist/connector/home.d.ts +13 -0
  60. package/dist/connector/home.d.ts.map +1 -0
  61. package/dist/connector/home.js +52 -0
  62. package/dist/connector/home.js.map +1 -0
  63. package/dist/connector/linked.d.ts +25 -0
  64. package/dist/connector/linked.d.ts.map +1 -0
  65. package/dist/connector/linked.js +24 -0
  66. package/dist/connector/linked.js.map +1 -0
  67. package/dist/connector/project-id.d.ts +17 -0
  68. package/dist/connector/project-id.d.ts.map +1 -0
  69. package/dist/connector/project-id.js +102 -0
  70. package/dist/connector/project-id.js.map +1 -0
  71. package/dist/connector/repo.d.ts +9 -0
  72. package/dist/connector/repo.d.ts.map +1 -0
  73. package/dist/connector/repo.js +41 -0
  74. package/dist/connector/repo.js.map +1 -0
  75. package/dist/connector/vault.d.ts +12 -0
  76. package/dist/connector/vault.d.ts.map +1 -0
  77. package/dist/connector/vault.js +27 -0
  78. package/dist/connector/vault.js.map +1 -0
  79. package/dist/index.d.ts +2 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +7 -0
  82. package/dist/index.js.map +1 -0
  83. package/dist/util/fs.d.ts +8 -0
  84. package/dist/util/fs.d.ts.map +1 -0
  85. package/dist/util/fs.js +36 -0
  86. package/dist/util/fs.js.map +1 -0
  87. package/dist/util/parse-args.d.ts +12 -0
  88. package/dist/util/parse-args.d.ts.map +1 -0
  89. package/dist/util/parse-args.js +49 -0
  90. package/dist/util/parse-args.js.map +1 -0
  91. package/dist/util/path.d.ts +10 -0
  92. package/dist/util/path.d.ts.map +1 -0
  93. package/dist/util/path.js +22 -0
  94. package/dist/util/path.js.map +1 -0
  95. package/dist/util/project-id.d.ts +2 -0
  96. package/dist/util/project-id.d.ts.map +1 -0
  97. package/dist/util/project-id.js +8 -0
  98. package/dist/util/project-id.js.map +1 -0
  99. package/dist/util/prompt.d.ts +2 -0
  100. package/dist/util/prompt.d.ts.map +1 -0
  101. package/dist/util/prompt.js +19 -0
  102. package/dist/util/prompt.js.map +1 -0
  103. package/dist/util/timestamp-slug.d.ts +38 -0
  104. package/dist/util/timestamp-slug.d.ts.map +1 -0
  105. package/dist/util/timestamp-slug.js +66 -0
  106. package/dist/util/timestamp-slug.js.map +1 -0
  107. package/dist/util/yaml.d.ts +6 -0
  108. package/dist/util/yaml.d.ts.map +1 -0
  109. package/dist/util/yaml.js +13 -0
  110. package/dist/util/yaml.js.map +1 -0
  111. package/dist/vault/layout.d.ts +13 -0
  112. package/dist/vault/layout.d.ts.map +1 -0
  113. package/dist/vault/layout.js +22 -0
  114. package/dist/vault/layout.js.map +1 -0
  115. package/dist/vault/list-handoffs.d.ts +10 -0
  116. package/dist/vault/list-handoffs.d.ts.map +1 -0
  117. package/dist/vault/list-handoffs.js +30 -0
  118. package/dist/vault/list-handoffs.js.map +1 -0
  119. package/dist/vault/write-handoff.d.ts +21 -0
  120. package/dist/vault/write-handoff.d.ts.map +1 -0
  121. package/dist/vault/write-handoff.js +40 -0
  122. package/dist/vault/write-handoff.js.map +1 -0
  123. package/dist/vault/write-note.d.ts +11 -0
  124. package/dist/vault/write-note.d.ts.map +1 -0
  125. package/dist/vault/write-note.js +15 -0
  126. package/dist/vault/write-note.js.map +1 -0
  127. package/package.json +45 -10
  128. package/templates/agents/claude/commands/grounder-note.md +11 -0
  129. package/templates/agents/claude/commands/grounder-task-handoff.md +54 -0
  130. package/templates/agents/claude/commands/grounder-task.md +20 -0
  131. package/templates/agents/cursor/commands/grounder-note.md +11 -0
  132. package/templates/agents/cursor/commands/grounder-task-handoff.md +54 -0
  133. package/templates/agents/cursor/commands/grounder-task.md +20 -0
  134. package/templates/vault/session-handoff.md +19 -0
  135. package/index.js +0 -1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Grounder contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,170 @@
1
- # grounder
1
+ # Grounder
2
2
 
3
- Setting up Git connections for Obsidian vaults to play nice with AI agents.
3
+ Connect project folders to a personal Obsidian vault so AI agents (Cursor, Claude Code, etc.) get persistent memory without committing personal docs to the repo.
4
+
5
+ **Requirements:** Node.js 18+ and an Obsidian vault on disk. Git is optional but used when present (project id detection and link lookup bounds).
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install -g grounder
11
+ ```
12
+
13
+ Or run without installing:
14
+
15
+ ```bash
16
+ npx grounder --help
17
+ ```
18
+
19
+ ## Quickstart
20
+
21
+ ```bash
22
+ # Once per machine — set vault location + install agent slash commands
23
+ grounder vault init ~/Documents/obsidian/dev
24
+
25
+ # Once per folder — link project id to vault notes/ + logs/
26
+ cd your-project
27
+ grounder init
28
+
29
+ # Write a note (or use /grounder-note in Cursor / Claude Code)
30
+ grounder note "Investigate auth middleware"
31
+
32
+ # End a session with a structured handoff (or use /grounder-task-handoff)
33
+ grounder handoff "$(cat <<'EOF'
34
+ # Handoff: auth middleware
35
+
36
+ ## Done
37
+ - Mapped middleware order
38
+
39
+ ## Next
40
+ 1. Add tests for 401 path
41
+
42
+ ## Blockers
43
+ - None
44
+
45
+ ## Decisions
46
+ - Keep cookie session for now
47
+
48
+ ## Files
49
+ - src/middleware/auth.ts
50
+ EOF
51
+ )"
52
+
53
+ # Next session — hydrate from newest handoff (or use /grounder-task)
54
+ grounder handoff list
55
+ ```
56
+
57
+ Notes land in `<vault>/10-Projects/{projectId}/notes/`.
58
+ Handoffs land in `<vault>/10-Projects/{projectId}/logs/` (one file per close; newest wins).
59
+
60
+ ### Session loop
61
+
62
+ ```text
63
+ /grounder-task → work → /grounder-task-handoff → next /grounder-task
64
+ ```
65
+
66
+ | Slash command | CLI | Role |
67
+ | --- | --- | --- |
68
+ | `/grounder-note` | `grounder note` | Ad-hoc vault note |
69
+ | `/grounder-task-handoff` | `grounder handoff` | Write session checkpoint to `logs/` |
70
+ | `/grounder-task` | `grounder handoff list` + read newest | Read-only hydrate from newest handoff + `AGENTS.md` |
71
+
72
+ ## Setup overview
73
+
74
+ Three steps — vault once per machine, then link each project folder:
75
+
76
+ 1. **`grounder vault init <path>`** (once per machine)
77
+ - Writes `~/.grounder/config.json` with the vault root
78
+ - Creates `<vault>/10-Projects/` if missing
79
+ - Installs agent slash commands for detected agents (or `--agent=<id>`):
80
+ - Cursor → `~/.cursor/commands/grounder-{note,task,task-handoff}.md`
81
+ - Claude Code → `~/.claude/commands/grounder-{note,task,task-handoff}.md`
82
+
83
+ 2. **`grounder init`** (once per project folder)
84
+ - Writes `.grounder.json` in the current directory (`projectId` — safe to commit)
85
+ - Creates `<vault>/10-Projects/{projectId}/notes/` and `logs/`
86
+
87
+ 3. **Daily use** — notes, handoffs, and recall via CLI or slash commands; no further install.
88
+
89
+ Nothing is written into the repo except the small `.grounder.json` marker. Agent artifacts stay under the user’s home directory; vault notes stay outside the project tree.
90
+
91
+ ## Commands
92
+
93
+ ```text
94
+ grounder vault init <path> Initialize vault + home config (once per machine)
95
+ grounder init Connect the current folder to your vault
96
+ grounder note <text> Write a note to the vault
97
+ grounder handoff <text> Write a session handoff to vault logs/
98
+ grounder handoff list Print recent handoff paths (newest first)
99
+ grounder path notes Print resolved notes directory
100
+ grounder path logs Print resolved logs directory
101
+ ```
102
+
103
+ ### Init flags
104
+
105
+ | Flag | Commands | Description |
106
+ | --- | --- | --- |
107
+ | `--yes` | `vault init`, `init` | Skip confirmation prompts |
108
+ | `--force` | `vault init`, `init` | Overwrite existing generated files |
109
+ | `--id <id>` | `init` | Override detected project id |
110
+ | `--vault <path>` | `init` | Override home vault root for this run |
111
+ | `--agent <id>` | `vault init` | Install for a specific agent (repeatable; default: auto-detect). Supported: `cursor`, `claude` |
112
+
113
+ ### Note / handoff flags
114
+
115
+ | Flag | Commands | Description |
116
+ | --- | --- | --- |
117
+ | `--title <slug>` | `note`, `handoff` | Filename slug (default: slugified text / first line) |
118
+ | `--limit <n>` | `handoff list` | Max paths to print (default: 5) |
119
+
120
+ Run `grounder --help` for the full reference.
121
+
122
+ ## Configuration
123
+
124
+ **Machine config** — `~/.grounder/config.json`:
125
+
126
+ ```json
127
+ { "vaultRoot": "/path/to/your/vault" }
128
+ ```
129
+
130
+ Written by `grounder vault init`. Holds the vault path for this machine only.
131
+
132
+ **Link marker** — `.grounder.json` in the folder where you run `grounder init` (safe to commit):
133
+
134
+ ```json
135
+ { "version": 1, "projectId": "your-project" }
136
+ ```
137
+
138
+ Written by `grounder init` in the **current working directory**. Project id detection (when `--id` is omitted): `package.json` name in that folder → git `origin` remote (if inside a git repo) → folder basename.
139
+
140
+ `grounder note`, `grounder handoff`, and `grounder path *` walk up from the current directory to find the nearest `.grounder.json`, stopping at the git root when one exists (or at the filesystem root otherwise).
141
+
142
+ **Environment variables**
143
+
144
+ | Variable | Description |
145
+ | --- | --- |
146
+ | `GROUNDER_VAULT` | Override vault root for the current session |
147
+ | `GROUNDER_HOME` | Override home directory (default: `~`) for config resolution |
148
+
149
+ ## Agents
150
+
151
+ The vault layout is agent-agnostic. `grounder vault init` installs thin glue artifacts per detected agent via a pluggable adapter registry (`src/agents/`).
152
+
153
+ | Agent | Detection | Artifacts |
154
+ | --- | --- | --- |
155
+ | Cursor | `~/.cursor` exists | `~/.cursor/commands/grounder-{note,task,task-handoff}.md` |
156
+ | Claude Code | `~/.claude` exists | `~/.claude/commands/grounder-{note,task,task-handoff}.md` |
157
+
158
+ No `--agent` flag: auto-detect installed agents. Explicit install:
159
+
160
+ ```bash
161
+ grounder vault init ~/Documents/obsidian/dev --agent=cursor --agent=claude
162
+ ```
163
+
164
+ Slash commands tell the agent to run `npx grounder …` from the linked project folder (no global install required). Re-run with `--force` to refresh existing installs.
165
+
166
+ Templates live under `templates/agents/{id}/`. Adding another agent means one adapter file + one template directory — `vault init` stays agent-blind.
167
+
168
+ ## Development
169
+
170
+ Source, tests, and contribution workflow live in the [Grounder monorepo](https://github.com/andrej-kolic/grounder).
@@ -0,0 +1,7 @@
1
+ import type { AgentAdapter } from "./types.js";
2
+ export declare function claudeCommandsDir(homeDir?: string): string;
3
+ export declare function grounderNoteCommandPath(homeDir?: string): string;
4
+ export declare function grounderTaskHandoffCommandPath(homeDir?: string): string;
5
+ export declare function grounderTaskCommandPath(homeDir?: string): string;
6
+ export declare const claude: AgentAdapter;
7
+ //# sourceMappingURL=claude.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude.d.ts","sourceRoot":"","sources":["../../src/agents/claude.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,YAAY,EAIb,MAAM,YAAY,CAAC;AAOpB,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,wBAAgB,8BAA8B,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhE;AAkBD,eAAO,MAAM,MAAM,EAAE,YAgBpB,CAAC"}
@@ -0,0 +1,46 @@
1
+ import { copyFile, mkdir } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { resolveHomeDir } from "../connector/home.js";
5
+ import { fileExists } from "../util/fs.js";
6
+ const pkgRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
7
+ const templateDir = path.join(pkgRoot, "templates", "agents", "claude", "commands");
8
+ const COMMANDS = ["grounder-note.md", "grounder-task-handoff.md", "grounder-task.md"];
9
+ export function claudeCommandsDir(homeDir) {
10
+ return path.join(resolveHomeDir(homeDir), ".claude", "commands");
11
+ }
12
+ export function grounderNoteCommandPath(homeDir) {
13
+ return path.join(claudeCommandsDir(homeDir), "grounder-note.md");
14
+ }
15
+ export function grounderTaskHandoffCommandPath(homeDir) {
16
+ return path.join(claudeCommandsDir(homeDir), "grounder-task-handoff.md");
17
+ }
18
+ export function grounderTaskCommandPath(homeDir) {
19
+ return path.join(claudeCommandsDir(homeDir), "grounder-task.md");
20
+ }
21
+ async function installCommand(filename, opts) {
22
+ const dest = path.join(claudeCommandsDir(opts.homeDir), filename);
23
+ const existed = await fileExists(dest);
24
+ if (existed && !opts.force) {
25
+ return { dest, status: "skipped" };
26
+ }
27
+ await mkdir(path.dirname(dest), { recursive: true });
28
+ await copyFile(path.join(templateDir, filename), dest);
29
+ return { dest, status: existed ? "overwritten" : "created" };
30
+ }
31
+ export const claude = {
32
+ id: "claude",
33
+ name: "Claude Code",
34
+ async isInstalled() {
35
+ return fileExists(path.join(resolveHomeDir(), ".claude"));
36
+ },
37
+ async install(opts) {
38
+ const artifacts = {};
39
+ for (const filename of COMMANDS) {
40
+ const { dest, status } = await installCommand(filename, opts);
41
+ artifacts[dest] = status;
42
+ }
43
+ return { artifacts };
44
+ },
45
+ };
46
+ //# sourceMappingURL=claude.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/agents/claude.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { AgentAdapter } from "./types.js";
2
+ export declare function cursorCommandsDir(homeDir?: string): string;
3
+ export declare function grounderNoteCommandPath(homeDir?: string): string;
4
+ export declare function grounderTaskHandoffCommandPath(homeDir?: string): string;
5
+ export declare function grounderTaskCommandPath(homeDir?: string): string;
6
+ export declare const cursor: AgentAdapter;
7
+ //# sourceMappingURL=cursor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../src/agents/cursor.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,YAAY,EAIb,MAAM,YAAY,CAAC;AAOpB,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,wBAAgB,8BAA8B,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhE;AAkBD,eAAO,MAAM,MAAM,EAAE,YAgBpB,CAAC"}
@@ -0,0 +1,46 @@
1
+ import { copyFile, mkdir } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { resolveHomeDir } from "../connector/home.js";
5
+ import { fileExists } from "../util/fs.js";
6
+ const pkgRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
7
+ const templateDir = path.join(pkgRoot, "templates", "agents", "cursor", "commands");
8
+ const COMMANDS = ["grounder-note.md", "grounder-task-handoff.md", "grounder-task.md"];
9
+ export function cursorCommandsDir(homeDir) {
10
+ return path.join(resolveHomeDir(homeDir), ".cursor", "commands");
11
+ }
12
+ export function grounderNoteCommandPath(homeDir) {
13
+ return path.join(cursorCommandsDir(homeDir), "grounder-note.md");
14
+ }
15
+ export function grounderTaskHandoffCommandPath(homeDir) {
16
+ return path.join(cursorCommandsDir(homeDir), "grounder-task-handoff.md");
17
+ }
18
+ export function grounderTaskCommandPath(homeDir) {
19
+ return path.join(cursorCommandsDir(homeDir), "grounder-task.md");
20
+ }
21
+ async function installCommand(filename, opts) {
22
+ const dest = path.join(cursorCommandsDir(opts.homeDir), filename);
23
+ const existed = await fileExists(dest);
24
+ if (existed && !opts.force) {
25
+ return { dest, status: "skipped" };
26
+ }
27
+ await mkdir(path.dirname(dest), { recursive: true });
28
+ await copyFile(path.join(templateDir, filename), dest);
29
+ return { dest, status: existed ? "overwritten" : "created" };
30
+ }
31
+ export const cursor = {
32
+ id: "cursor",
33
+ name: "Cursor",
34
+ async isInstalled() {
35
+ return fileExists(path.join(resolveHomeDir(), ".cursor"));
36
+ },
37
+ async install(opts) {
38
+ const artifacts = {};
39
+ for (const filename of COMMANDS) {
40
+ const { dest, status } = await installCommand(filename, opts);
41
+ artifacts[dest] = status;
42
+ }
43
+ return { artifacts };
44
+ },
45
+ };
46
+ //# sourceMappingURL=cursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../src/agents/cursor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { AgentAdapter } from "./types.js";
2
+ export { claude } from "./claude.js";
3
+ export { cursor } from "./cursor.js";
4
+ export type { AgentAdapter, AgentInstallOptions, AgentInstallResult, ArtifactStatus, } from "./types.js";
5
+ /**
6
+ * Resolve which adapters to run:
7
+ * - If `ids` is provided, return those adapters (throws on unknown id).
8
+ * - Otherwise, auto-detect by checking isInstalled() for each adapter.
9
+ */
10
+ export declare function resolveAgents(ids?: string[]): Promise<AgentAdapter[]>;
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EACV,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,GACf,MAAM,YAAY,CAAC;AAIpB;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAc3E"}
@@ -0,0 +1,23 @@
1
+ import { claude } from "./claude.js";
2
+ import { cursor } from "./cursor.js";
3
+ export { claude } from "./claude.js";
4
+ export { cursor } from "./cursor.js";
5
+ const ALL_ADAPTERS = [cursor, claude];
6
+ /**
7
+ * Resolve which adapters to run:
8
+ * - If `ids` is provided, return those adapters (throws on unknown id).
9
+ * - Otherwise, auto-detect by checking isInstalled() for each adapter.
10
+ */
11
+ export async function resolveAgents(ids) {
12
+ if (ids && ids.length > 0) {
13
+ const found = ALL_ADAPTERS.filter((a) => ids.includes(a.id));
14
+ const unknown = ids.filter((id) => !ALL_ADAPTERS.some((a) => a.id === id));
15
+ if (unknown.length > 0) {
16
+ throw new Error(`Unknown agent id(s): ${unknown.join(", ")}`);
17
+ }
18
+ return found;
19
+ }
20
+ const results = await Promise.all(ALL_ADAPTERS.map(async (a) => ({ adapter: a, ok: await a.isInstalled() })));
21
+ return results.filter((r) => r.ok).map((r) => r.adapter);
22
+ }
23
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAQrC,MAAM,YAAY,GAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEtD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAc;IAChD,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC7D,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QAC3E,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,wBAAwB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAChE,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAC3E,CAAC;IACF,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,20 @@
1
+ export type ArtifactStatus = "created" | "skipped" | "overwritten";
2
+ export interface AgentInstallOptions {
3
+ force?: boolean;
4
+ homeDir?: string;
5
+ }
6
+ export interface AgentInstallResult {
7
+ /** Map of installed file path → what happened to it. */
8
+ artifacts: Record<string, ArtifactStatus>;
9
+ }
10
+ export interface AgentAdapter {
11
+ /** Stable lowercase id used in config and flags, e.g. "cursor". */
12
+ readonly id: string;
13
+ /** Human-readable display name, e.g. "Cursor". */
14
+ readonly name: string;
15
+ /** Returns true when this agent appears to be installed on the machine. */
16
+ isInstalled(): Promise<boolean>;
17
+ /** Install all agent-specific artifacts (commands, rules, etc.). */
18
+ install(opts: AgentInstallOptions): Promise<AgentInstallResult>;
19
+ }
20
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/agents/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAC;AAEnE,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,YAAY;IAC3B,mEAAmE;IACnE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC,oEAAoE;IACpE,OAAO,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACjE"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/agents/types.ts"],"names":[],"mappings":""}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { runHandoffList } from "./commands/handoff/list.js";
6
+ import { runHandoff } from "./commands/handoff.js";
7
+ import { runNote } from "./commands/note.js";
8
+ import { runPathLogs } from "./commands/path/logs.js";
9
+ import { runPathNotes } from "./commands/path/notes.js";
10
+ import { runRepoInit } from "./commands/repo/init.js";
11
+ import { runVaultInit } from "./commands/vault/init.js";
12
+ const pkgRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
13
+ const pkg = JSON.parse(readFileSync(path.join(pkgRoot, "package.json"), "utf8"));
14
+ const USAGE = `grounder — connect git projects to Obsidian dev vaults for AI agents
15
+
16
+ Usage:
17
+ grounder vault init <path> Initialize vault + home config (once per machine)
18
+ grounder init Connect the current repo to your vault
19
+ grounder note <text> Write a note to the vault
20
+ grounder handoff <text> Write a session handoff to vault logs/
21
+ grounder handoff list Print recent handoff paths (newest first)
22
+ grounder path notes Print resolved notes directory
23
+ grounder path logs Print resolved logs directory
24
+
25
+ Options:
26
+ -h, --help Show this help
27
+ -v, --version Show version
28
+
29
+ Init flags:
30
+ --yes Skip confirmation prompts
31
+ --force Overwrite existing generated files
32
+ --id <id> Override detected project id (grounder init)
33
+ --vault <path> Override home vault root for this run (grounder init)
34
+ --agent <id> Install for a specific agent (repeatable; default: auto-detect)
35
+ Supported: cursor, claude
36
+
37
+ Note / handoff flags:
38
+ --title <slug> Short slug in filename (default: slugified first line)
39
+ --limit <n> Max paths for handoff list (default: 5)
40
+
41
+ Quickstart:
42
+ grounder vault init ~/Documents/obsidian/dev
43
+ grounder init
44
+ grounder note "my first note"
45
+ grounder handoff "# Handoff\\n\\n## Next\\n1. …"
46
+ grounder handoff list
47
+ `;
48
+ function printHelp() {
49
+ process.stdout.write(USAGE);
50
+ }
51
+ function printVersion() {
52
+ process.stdout.write(`${pkg.version}\n`);
53
+ }
54
+ async function main() {
55
+ const args = process.argv.slice(2);
56
+ if (args.length === 0 || args[0] === "-h" || args[0] === "--help") {
57
+ printHelp();
58
+ process.exit(0);
59
+ }
60
+ if (args[0] === "-v" || args[0] === "--version") {
61
+ printVersion();
62
+ return;
63
+ }
64
+ const [command, ...rest] = args;
65
+ if (command === "vault" && rest[0] === "init") {
66
+ process.exit(await runVaultInit(rest.slice(1)));
67
+ }
68
+ if (command === "init") {
69
+ process.exit(await runRepoInit(rest));
70
+ }
71
+ if (command === "note") {
72
+ process.exit(await runNote(rest));
73
+ }
74
+ if (command === "handoff" && rest[0] === "list") {
75
+ process.exit(await runHandoffList(rest.slice(1)));
76
+ }
77
+ if (command === "handoff") {
78
+ process.exit(await runHandoff(rest));
79
+ }
80
+ if (command === "path" && rest[0] === "notes") {
81
+ process.exit(await runPathNotes(rest.slice(1)));
82
+ }
83
+ if (command === "path" && rest[0] === "logs") {
84
+ process.exit(await runPathLogs(rest.slice(1)));
85
+ }
86
+ process.stderr.write(`Unknown command: ${args.join(" ")}\n\n`);
87
+ printHelp();
88
+ process.exit(1);
89
+ }
90
+ main().catch((error) => {
91
+ const message = error instanceof Error ? error.message : String(error);
92
+ process.stderr.write(`${message}\n`);
93
+ process.exit(1);
94
+ });
95
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /** Options for {@link runHandoffListWithOptions} (CLI parsing and tests). */
2
+ export interface HandoffListOptions {
3
+ /** Directory used to find the linked repo (default: `process.cwd()`). */
4
+ cwd?: string;
5
+ /** Max paths to print, newest first (default: 5). */
6
+ limit?: number;
7
+ /** Override home dir / `GROUNDER_HOME` (tests). */
8
+ homeDir?: string;
9
+ }
10
+ /**
11
+ * CLI entry for `grounder handoff list [--limit <n>]`.
12
+ * `--limit` must be a positive integer when provided.
13
+ * @returns Exit code (`0` on success, `1` on usage or config errors).
14
+ */
15
+ export declare function runHandoffList(argv: string[]): Promise<number>;
16
+ /**
17
+ * Resolves the linked project, lists recent handoff paths under `logs/` (newest first).
18
+ * Prints one absolute path per line; empty when no handoffs. Same vault/link
19
+ * prerequisites as `grounder handoff`.
20
+ * @returns Exit code (`0` on success, `1` when vault/link is missing).
21
+ */
22
+ export declare function runHandoffListWithOptions(options?: HandoffListOptions): Promise<number>;
23
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/commands/handoff/list.ts"],"names":[],"mappings":"AAQA,6EAA6E;AAC7E,MAAM,WAAW,kBAAkB;IACjC,yEAAyE;IACzE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AASD;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA2BpE;AAED;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAAC,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBjG"}
@@ -0,0 +1,64 @@
1
+ import { withHomeDir } from "../../connector/home.js";
2
+ import { resolveLogsDir } from "../../connector/vault.js";
3
+ import { parseArgs } from "../../util/parse-args.js";
4
+ import { listHandoffs } from "../../vault/list-handoffs.js";
5
+ import { requireLinkedProject } from "../require-linked.js";
6
+ const DEFAULT_LIMIT = 5;
7
+ const USAGE = "Usage: grounder handoff list [--limit <n>]\n";
8
+ function usageError() {
9
+ process.stderr.write(USAGE);
10
+ return 1;
11
+ }
12
+ /**
13
+ * CLI entry for `grounder handoff list [--limit <n>]`.
14
+ * `--limit` must be a positive integer when provided.
15
+ * @returns Exit code (`0` on success, `1` on usage or config errors).
16
+ */
17
+ export async function runHandoffList(argv) {
18
+ const { positional, flags } = parseArgs(argv);
19
+ if (positional.length > 0) {
20
+ return usageError();
21
+ }
22
+ for (const key of flags.keys()) {
23
+ if (key !== "limit") {
24
+ return usageError();
25
+ }
26
+ }
27
+ const limitRaw = flags.get("limit");
28
+ let limit = DEFAULT_LIMIT;
29
+ if (limitRaw !== undefined) {
30
+ if (typeof limitRaw !== "string") {
31
+ return usageError();
32
+ }
33
+ const trimmed = limitRaw.trim();
34
+ const parsed = Number.parseInt(trimmed, 10);
35
+ if (!/^\d+$/.test(trimmed) || Number.isNaN(parsed) || parsed < 1) {
36
+ return usageError();
37
+ }
38
+ limit = parsed;
39
+ }
40
+ return runHandoffListWithOptions({ limit });
41
+ }
42
+ /**
43
+ * Resolves the linked project, lists recent handoff paths under `logs/` (newest first).
44
+ * Prints one absolute path per line; empty when no handoffs. Same vault/link
45
+ * prerequisites as `grounder handoff`.
46
+ * @returns Exit code (`0` on success, `1` when vault/link is missing).
47
+ */
48
+ export async function runHandoffListWithOptions(options = {}) {
49
+ return withHomeDir(options.homeDir, async () => {
50
+ const linked = await requireLinkedProject(options.cwd ?? process.cwd());
51
+ if (!linked) {
52
+ return 1;
53
+ }
54
+ const logsDir = resolveLogsDir(linked.home, linked.repo);
55
+ const paths = await listHandoffs(logsDir, {
56
+ limit: options.limit ?? DEFAULT_LIMIT,
57
+ });
58
+ for (const filePath of paths) {
59
+ process.stdout.write(`${filePath}\n`);
60
+ }
61
+ return 0;
62
+ });
63
+ }
64
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/commands/handoff/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE5D,MAAM,aAAa,GAAG,CAAC,CAAC;AAYxB,MAAM,KAAK,GAAG,8CAA8C,CAAC;AAE7D,SAAS,UAAU;IACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC5B,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAc;IACjD,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC9C,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,OAAO,UAAU,EAAE,CAAC;IACtB,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QAC/B,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;YACpB,OAAO,UAAU,EAAE,CAAC;QACtB,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACpC,IAAI,KAAK,GAAG,aAAa,CAAC;IAC1B,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACjC,OAAO,UAAU,EAAE,CAAC;QACtB,CAAC;QACD,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC5C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;YACjE,OAAO,UAAU,EAAE,CAAC;QACtB,CAAC;QACD,KAAK,GAAG,MAAM,CAAC;IACjB,CAAC;IAED,OAAO,yBAAyB,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,UAA8B,EAAE;IAC9E,OAAO,WAAW,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE;QAC7C,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QACxE,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,CAAC;QACX,CAAC;QAED,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QACzD,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE;YACxC,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,aAAa;SACtC,CAAC,CAAC;QAEH,KAAK,MAAM,QAAQ,IAAI,KAAK,EAAE,CAAC;YAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,QAAQ,IAAI,CAAC,CAAC;QACxC,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,25 @@
1
+ /** Options for {@link runHandoffWithOptions} (CLI parsing and tests). */
2
+ export interface HandoffOptions {
3
+ /** Directory used to find the linked repo (default: `process.cwd()`). */
4
+ cwd?: string;
5
+ /** Markdown body stored under the project `logs/` folder. */
6
+ text: string;
7
+ /** Optional filename + frontmatter title slug (`--title`). */
8
+ title?: string;
9
+ /** Override home dir / `GROUNDER_HOME` (tests). */
10
+ homeDir?: string;
11
+ /** Fixed clock for deterministic filenames and `created` (tests). */
12
+ now?: Date;
13
+ }
14
+ /**
15
+ * CLI entry for `grounder handoff <text> [--title <slug>]`.
16
+ * @returns Exit code (`0` on success, `1` on usage or config errors).
17
+ */
18
+ export declare function runHandoff(argv: string[]): Promise<number>;
19
+ /**
20
+ * Resolves the linked project, writes a new handoff under `logs/`, prints `Wrote <path>`.
21
+ * Same vault/link prerequisites as `grounder note`.
22
+ * @returns Exit code (`0` on success, `1` when vault/link is missing).
23
+ */
24
+ export declare function runHandoffWithOptions(options: HandoffOptions): Promise<number>;
25
+ //# sourceMappingURL=handoff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handoff.d.ts","sourceRoot":"","sources":["../../src/commands/handoff.ts"],"names":[],"mappings":"AAOA,yEAAyE;AACzE,MAAM,WAAW,cAAc;IAC7B,yEAAyE;IACzE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAahE;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAoBpF"}