opencarly 1.0.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 (59) hide show
  1. package/README.md +78 -0
  2. package/bin/install.js +304 -0
  3. package/commands/carly-manager.md +69 -0
  4. package/dist/config/discovery.d.ts +22 -0
  5. package/dist/config/discovery.d.ts.map +1 -0
  6. package/dist/config/discovery.js +43 -0
  7. package/dist/config/discovery.js.map +1 -0
  8. package/dist/config/index.d.ts +7 -0
  9. package/dist/config/index.d.ts.map +1 -0
  10. package/dist/config/index.js +7 -0
  11. package/dist/config/index.js.map +1 -0
  12. package/dist/config/manifest.d.ts +39 -0
  13. package/dist/config/manifest.d.ts.map +1 -0
  14. package/dist/config/manifest.js +139 -0
  15. package/dist/config/manifest.js.map +1 -0
  16. package/dist/config/schema.d.ts +663 -0
  17. package/dist/config/schema.d.ts.map +1 -0
  18. package/dist/config/schema.js +208 -0
  19. package/dist/config/schema.js.map +1 -0
  20. package/dist/engine/brackets.d.ts +26 -0
  21. package/dist/engine/brackets.d.ts.map +1 -0
  22. package/dist/engine/brackets.js +49 -0
  23. package/dist/engine/brackets.js.map +1 -0
  24. package/dist/engine/index.d.ts +8 -0
  25. package/dist/engine/index.d.ts.map +1 -0
  26. package/dist/engine/index.js +8 -0
  27. package/dist/engine/index.js.map +1 -0
  28. package/dist/engine/loader.d.ts +82 -0
  29. package/dist/engine/loader.d.ts.map +1 -0
  30. package/dist/engine/loader.js +147 -0
  31. package/dist/engine/loader.js.map +1 -0
  32. package/dist/engine/matcher.d.ts +43 -0
  33. package/dist/engine/matcher.d.ts.map +1 -0
  34. package/dist/engine/matcher.js +174 -0
  35. package/dist/engine/matcher.js.map +1 -0
  36. package/dist/engine/trimmer.d.ts +91 -0
  37. package/dist/engine/trimmer.d.ts.map +1 -0
  38. package/dist/engine/trimmer.js +236 -0
  39. package/dist/engine/trimmer.js.map +1 -0
  40. package/dist/formatter/formatter.d.ts +23 -0
  41. package/dist/formatter/formatter.d.ts.map +1 -0
  42. package/dist/formatter/formatter.js +129 -0
  43. package/dist/formatter/formatter.js.map +1 -0
  44. package/dist/index.d.ts +15 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +484 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/session/session.d.ts +60 -0
  49. package/dist/session/session.d.ts.map +1 -0
  50. package/dist/session/session.js +394 -0
  51. package/dist/session/session.js.map +1 -0
  52. package/package.json +59 -0
  53. package/templates/.opencarly/commands.json +96 -0
  54. package/templates/.opencarly/context.json +44 -0
  55. package/templates/.opencarly/domains/development.md +13 -0
  56. package/templates/.opencarly/domains/global.md +13 -0
  57. package/templates/.opencarly/domains/security.md +14 -0
  58. package/templates/.opencarly/domains/testing.md +12 -0
  59. package/templates/.opencarly/manifest.json +43 -0
package/README.md ADDED
@@ -0,0 +1,78 @@
1
+ # OpenCarly
2
+
3
+ **Context Augmentation & Reinforcement Layer for OpenCode**
4
+
5
+ OpenCarly is an intelligent plugin for [OpenCode](https://github.com/opencode-ai/opencode) that dynamically manages your AI's context window. Instead of dumping all your rules, API guidelines, and project instructions into a single massive prompt, OpenCarly loads rules *only when they are relevant* and seamlessly trims them from the chat history when they aren't.
6
+
7
+ This saves massive amounts of tokens, dramatically reduces your API costs, and keeps your AI laser-focused on the task at hand without being distracted by irrelevant guidelines.
8
+
9
+ ## 🚀 Features
10
+
11
+ - **Dynamic Rule Injection:** Automatically injects specific instructions based on the files currently loaded in your context (e.g., injects `React` rules only when a `.tsx` file is open).
12
+ - **Keyword Triggers:** Trigger rule injection simply by typing a keyword in your prompt (e.g., typing "*api" injects your backend API guidelines).
13
+ - **History Trimming:** Aggressively removes injected rules from previous messages in the chat history, ensuring you only pay for the context once.
14
+ - **Cost Estimation & Stats:** Run `*stats` at any time to see exactly how many tokens (and estimated dollars!) OpenCarly has saved you.
15
+
16
+ ## 📦 Installation
17
+
18
+ To install OpenCarly globally, use npm:
19
+
20
+ ```bash
21
+ npm install -g opencarly
22
+ ```
23
+
24
+ Then, initialize OpenCarly in your project directory:
25
+
26
+ ```bash
27
+ cd your-project-dir
28
+ npx opencarly init
29
+ ```
30
+
31
+ This will create an `.opencarly` configuration directory in your project containing a `config.json` file and a `rules/` folder where you can place your dynamic guidelines.
32
+
33
+ ## ⚙️ Configuration
34
+
35
+ Open your newly created `.opencarly/config.json` to start adding rules.
36
+
37
+ A rule consists of:
38
+ - `name`: A descriptive name for the rule.
39
+ - `files`: (Optional) An array of file globs. The rule will automatically inject if any file matching these globs is loaded in OpenCode.
40
+ - `keywords`: (Optional) An array of keywords. The rule will inject if any of these words (prefixed with a `*`, like `*sql`) are typed in your prompt.
41
+ - `content`: The path to the markdown file containing your instructions (relative to the `.opencarly/rules/` directory).
42
+
43
+ ### Example Configuration
44
+
45
+ ```json
46
+ {
47
+ "rules": [
48
+ {
49
+ "name": "React Guidelines",
50
+ "files": ["**/*.tsx", "**/*.jsx", "components/**/*"],
51
+ "content": "react.md"
52
+ },
53
+ {
54
+ "name": "Database Schema",
55
+ "keywords": ["db", "sql", "database"],
56
+ "content": "schema.md"
57
+ }
58
+ ]
59
+ }
60
+ ```
61
+
62
+ With this setup:
63
+ - Editing a `Button.tsx` file will automatically inject the rules from `react.md`.
64
+ - Asking the AI "Please write a *sql query" will automatically inject the rules from `schema.md`.
65
+
66
+ ## 📊 Viewing Token Savings
67
+
68
+ You can see how many tokens OpenCarly has saved you by using the built-in stats command inside OpenCode:
69
+
70
+ ```text
71
+ user: *stats
72
+ ```
73
+
74
+ OpenCarly will output a detailed report showing total tokens trimmed, prompts processed, and an estimated dollar amount saved based on your current AI model's input token pricing.
75
+
76
+ ## 📝 License
77
+
78
+ MIT
package/bin/install.js ADDED
@@ -0,0 +1,304 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * OpenCarly Installer
5
+ *
6
+ * Sets up the .opencarly/ configuration directory and registers the plugin
7
+ * with OpenCode.
8
+ *
9
+ * Usage:
10
+ * npx opencarly # Interactive install
11
+ * npx opencarly --local # Install to ./.opencarly/ (non-interactive)
12
+ * npx opencarly --global # Install to ~/.config/opencarly/ (non-interactive)
13
+ * npx opencarly --skip-agents-md # Don't modify AGENTS.md
14
+ */
15
+
16
+ const fs = require("fs");
17
+ const path = require("path");
18
+ const os = require("os");
19
+ const readline = require("readline");
20
+
21
+ // ---------------------------------------------------------------------------
22
+ // Constants
23
+ // ---------------------------------------------------------------------------
24
+
25
+ const PACKAGE_ROOT = path.resolve(__dirname, "..");
26
+ const TEMPLATES_DIR = path.join(PACKAGE_ROOT, "templates", ".opencarly");
27
+ const COMMANDS_DIR = path.join(PACKAGE_ROOT, "commands");
28
+
29
+ const AGENTS_MD_BLOCK = `
30
+ <!-- OPENCARLY-MANAGED: Do not remove this section -->
31
+ ## OpenCarly Integration
32
+
33
+ Follow all rules in <carly-rules> blocks injected into the system prompt.
34
+ These are dynamically injected based on context and MUST be obeyed.
35
+ They take precedence over general instructions when present.
36
+ <!-- END OPENCARLY-MANAGED -->
37
+ `;
38
+
39
+ // ---------------------------------------------------------------------------
40
+ // Helpers
41
+ // ---------------------------------------------------------------------------
42
+
43
+ function ask(rl, question) {
44
+ return new Promise((resolve) => {
45
+ rl.question(question, (answer) => resolve(answer.trim()));
46
+ });
47
+ }
48
+
49
+ function copyDirRecursive(src, dest) {
50
+ if (!fs.existsSync(dest)) {
51
+ fs.mkdirSync(dest, { recursive: true });
52
+ }
53
+
54
+ const entries = fs.readdirSync(src, { withFileTypes: true });
55
+ for (const entry of entries) {
56
+ const srcPath = path.join(src, entry.name);
57
+ const destPath = path.join(dest, entry.name);
58
+
59
+ if (entry.isDirectory()) {
60
+ copyDirRecursive(srcPath, destPath);
61
+ } else {
62
+ // Don't overwrite existing files
63
+ if (!fs.existsSync(destPath)) {
64
+ fs.copyFileSync(srcPath, destPath);
65
+ console.log(` Created: ${destPath}`);
66
+ } else {
67
+ console.log(` Skipped (exists): ${destPath}`);
68
+ }
69
+ }
70
+ }
71
+ }
72
+
73
+ function ensureDir(dir) {
74
+ if (!fs.existsSync(dir)) {
75
+ fs.mkdirSync(dir, { recursive: true });
76
+ }
77
+ }
78
+
79
+ // ---------------------------------------------------------------------------
80
+ // Plugin registration
81
+ // ---------------------------------------------------------------------------
82
+
83
+ function registerPlugin(projectDir) {
84
+ const configPath = path.join(projectDir, "opencode.json");
85
+
86
+ let config = {};
87
+ if (fs.existsSync(configPath)) {
88
+ try {
89
+ config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
90
+ } catch {
91
+ console.log(" Warning: Could not parse existing opencode.json, creating new one");
92
+ config = {};
93
+ }
94
+ }
95
+
96
+ // Add opencarly to plugin array
97
+ if (!config.plugin) {
98
+ config.plugin = [];
99
+ }
100
+
101
+ if (!config.plugin.includes("opencarly")) {
102
+ config.plugin.push("opencarly");
103
+ }
104
+
105
+ // Ensure $schema is set
106
+ if (!config.$schema) {
107
+ config.$schema = "https://opencode.ai/config.json";
108
+ }
109
+
110
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
111
+ console.log(` Updated: ${configPath}`);
112
+ }
113
+
114
+ // ---------------------------------------------------------------------------
115
+ // AGENTS.md integration
116
+ // ---------------------------------------------------------------------------
117
+
118
+ function addAgentsMdBlock(projectDir) {
119
+ const agentsPath = path.join(projectDir, "AGENTS.md");
120
+
121
+ if (fs.existsSync(agentsPath)) {
122
+ const content = fs.readFileSync(agentsPath, "utf-8");
123
+
124
+ // Check if block already exists
125
+ if (content.includes("OPENCARLY-MANAGED")) {
126
+ console.log(" Skipped AGENTS.md (OpenCarly block already present)");
127
+ return;
128
+ }
129
+
130
+ // Insert after first heading, or at the end
131
+ const firstHeadingMatch = content.match(/^#[^#].+$/m);
132
+ let newContent;
133
+ if (firstHeadingMatch) {
134
+ const insertPos = content.indexOf(firstHeadingMatch[0]) + firstHeadingMatch[0].length;
135
+ newContent =
136
+ content.slice(0, insertPos) +
137
+ "\n" +
138
+ AGENTS_MD_BLOCK +
139
+ content.slice(insertPos);
140
+ } else {
141
+ newContent = content + "\n" + AGENTS_MD_BLOCK;
142
+ }
143
+
144
+ fs.writeFileSync(agentsPath, newContent, "utf-8");
145
+ console.log(` Updated: ${agentsPath}`);
146
+ } else {
147
+ // Create AGENTS.md with the block
148
+ fs.writeFileSync(
149
+ agentsPath,
150
+ `# Project Instructions\n${AGENTS_MD_BLOCK}`,
151
+ "utf-8"
152
+ );
153
+ console.log(` Created: ${agentsPath}`);
154
+ }
155
+ }
156
+
157
+ // ---------------------------------------------------------------------------
158
+ // Install custom commands
159
+ // ---------------------------------------------------------------------------
160
+
161
+ function installCommands(projectDir) {
162
+ const destDir = path.join(projectDir, ".opencode", "commands");
163
+ ensureDir(destDir);
164
+
165
+ if (fs.existsSync(COMMANDS_DIR)) {
166
+ const files = fs.readdirSync(COMMANDS_DIR);
167
+ for (const file of files) {
168
+ const srcPath = path.join(COMMANDS_DIR, file);
169
+ const destPath = path.join(destDir, file);
170
+
171
+ if (!fs.existsSync(destPath)) {
172
+ fs.copyFileSync(srcPath, destPath);
173
+ console.log(` Created: ${destPath}`);
174
+ } else {
175
+ console.log(` Skipped (exists): ${destPath}`);
176
+ }
177
+ }
178
+ }
179
+ }
180
+
181
+ // ---------------------------------------------------------------------------
182
+ // Main
183
+ // ---------------------------------------------------------------------------
184
+
185
+ async function main() {
186
+ const args = process.argv.slice(2);
187
+
188
+ const isGlobal = args.includes("--global") || args.includes("-g");
189
+ const isLocal = args.includes("--local") || args.includes("-l");
190
+ const skipAgentsMd = args.includes("--skip-agents-md");
191
+ const showHelp = args.includes("--help") || args.includes("-h");
192
+
193
+ if (showHelp) {
194
+ console.log(`
195
+ OpenCarly Installer - Dynamic rules for OpenCode
196
+
197
+ Usage:
198
+ npx opencarly Interactive install
199
+ npx opencarly --local Install to ./.opencarly/ (non-interactive)
200
+ npx opencarly --global Install to ~/.config/opencarly/ (non-interactive)
201
+
202
+ Options:
203
+ --local, -l Install to current project directory
204
+ --global, -g Install to global config directory
205
+ --skip-agents-md Don't modify AGENTS.md
206
+ --help, -h Show this help message
207
+ `);
208
+ process.exit(0);
209
+ }
210
+
211
+ console.log("");
212
+ console.log(" OpenCarly - Context Augmentation & Reinforcement Layer for OpenCode");
213
+ console.log(" Dynamic rules that load when relevant, disappear when not.");
214
+ console.log("");
215
+
216
+ let installScope;
217
+ let addBlock = !skipAgentsMd;
218
+
219
+ if (isGlobal) {
220
+ installScope = "global";
221
+ } else if (isLocal) {
222
+ installScope = "local";
223
+ } else {
224
+ // Interactive mode
225
+ const rl = readline.createInterface({
226
+ input: process.stdin,
227
+ output: process.stdout,
228
+ });
229
+
230
+ const scopeAnswer = await ask(
231
+ rl,
232
+ " Install location?\n 1) Local (this project only - ./.opencarly/)\n 2) Global (all projects - ~/.config/opencarly/)\n Choice [1]: "
233
+ );
234
+ installScope = scopeAnswer === "2" ? "global" : "local";
235
+
236
+ if (!skipAgentsMd) {
237
+ const agentsAnswer = await ask(
238
+ rl,
239
+ " Add OpenCarly integration block to AGENTS.md? [Y/n]: "
240
+ );
241
+ addBlock = agentsAnswer.toLowerCase() !== "n";
242
+ }
243
+
244
+ rl.close();
245
+ }
246
+
247
+ const cwd = process.cwd();
248
+ const targetDir =
249
+ installScope === "global"
250
+ ? path.join(os.homedir(), ".config", "opencarly")
251
+ : path.join(cwd, ".opencarly");
252
+
253
+ console.log("");
254
+ console.log(` Installing to: ${targetDir}`);
255
+ console.log("");
256
+
257
+ // 1. Copy templates
258
+ console.log(" [1/4] Copying configuration templates...");
259
+ copyDirRecursive(TEMPLATES_DIR, targetDir);
260
+
261
+ // 2. Create sessions directory
262
+ const sessionsDir = path.join(targetDir, "sessions");
263
+ ensureDir(sessionsDir);
264
+ const gitkeep = path.join(sessionsDir, ".gitkeep");
265
+ if (!fs.existsSync(gitkeep)) {
266
+ fs.writeFileSync(gitkeep, "", "utf-8");
267
+ }
268
+
269
+ // 3. Register plugin in opencode.json
270
+ console.log(" [2/4] Registering plugin in opencode.json...");
271
+ registerPlugin(cwd);
272
+
273
+ // 4. Add AGENTS.md block
274
+ if (addBlock) {
275
+ console.log(" [3/4] Adding integration block to AGENTS.md...");
276
+ addAgentsMdBlock(cwd);
277
+ } else {
278
+ console.log(" [3/4] Skipping AGENTS.md modification");
279
+ }
280
+
281
+ // 5. Install custom commands
282
+ console.log(" [4/4] Installing custom commands...");
283
+ installCommands(cwd);
284
+
285
+ console.log("");
286
+ console.log(" OpenCarly installed successfully!");
287
+ console.log("");
288
+ console.log(" Configuration: " + targetDir);
289
+ console.log(" Edit manifest: " + path.join(targetDir, "manifest.json"));
290
+ console.log(" Edit commands: " + path.join(targetDir, "commands.json"));
291
+ console.log(" Edit brackets: " + path.join(targetDir, "context.json"));
292
+ console.log(" Add domains: " + path.join(targetDir, "domains/"));
293
+ console.log("");
294
+ console.log(" Quick start:");
295
+ console.log(" Type *carly in OpenCode for an interactive guide");
296
+ console.log(" Type *dev, *brief, *plan, etc. for star-commands");
297
+ console.log(" Run /carly for domain management");
298
+ console.log("");
299
+ }
300
+
301
+ main().catch((err) => {
302
+ console.error("Installation failed:", err.message);
303
+ process.exit(1);
304
+ });
@@ -0,0 +1,69 @@
1
+ ---
2
+ description: Manage OpenCarly domains, commands, and settings
3
+ ---
4
+
5
+ You are now acting as the OpenCarly Configuration Manager.
6
+
7
+ ## Your Job
8
+
9
+ Help the user manage their OpenCarly configuration. OpenCarly is a dynamic rule injection system - it loads rules into the AI's context based on what the user is doing.
10
+
11
+ ## Configuration Files
12
+
13
+ All config lives in the `.opencarly/` directory:
14
+ - **manifest.json** - Domain registry and global settings
15
+ - **commands.json** - Star-command definitions (*dev, *brief, etc.)
16
+ - **context.json** - Context bracket thresholds and rules
17
+ - **domains/*.md** - Rule files (one per domain, rules as `- bullet points`)
18
+ - **sessions/*.json** - Auto-generated per-session state (don't edit manually)
19
+
20
+ ## What the User Can Ask You To Do
21
+
22
+ 1. **Show status**: Read manifest.json and show all domains, their states, and recall keywords
23
+ 2. **Toggle domain**: Change a domain's `state` between "active" and "inactive" in manifest.json
24
+ 3. **Create domain**: Create a new .md rule file in domains/ and add the domain entry to manifest.json
25
+ 4. **Edit rules**: Add, remove, or modify rules in a domain's .md file
26
+ 5. **Toggle DEVMODE**: Set `devmode` to true/false in manifest.json
27
+ 6. **Create star-command**: Add a new command to commands.json
28
+ 7. **Edit star-command**: Modify rules for an existing command in commands.json
29
+ 8. **Edit context brackets**: Modify thresholds or rules in context.json
30
+ 9. **Show session info**: Read the current session file from sessions/
31
+
32
+ ## How to Respond
33
+
34
+ First, read the current `.opencarly/manifest.json` to understand the current configuration.
35
+
36
+ If the user says "$ARGUMENTS", interpret that as their specific request. If no arguments, show the current status overview:
37
+ - List all domains with state, alwaysOn flag, and recall keywords
38
+ - Show whether DEVMODE is on/off
39
+ - Show whether commands and context systems are active
40
+ - List available star-commands
41
+
42
+ Always make changes by editing the actual files. Confirm what you changed.
43
+
44
+ ## Domain .md File Format
45
+
46
+ Rules are bullet points:
47
+ ```markdown
48
+ # Domain Name Rules
49
+
50
+ Optional description text.
51
+
52
+ - First rule
53
+ - Second rule
54
+ - Third rule
55
+ ```
56
+
57
+ ## manifest.json Domain Entry Format
58
+
59
+ ```json
60
+ {
61
+ "domain-name": {
62
+ "state": "active",
63
+ "alwaysOn": false,
64
+ "recall": ["keyword1", "keyword2"],
65
+ "exclude": [],
66
+ "file": "domains/domain-name.md"
67
+ }
68
+ }
69
+ ```
@@ -0,0 +1,22 @@
1
+ /**
2
+ * OpenCarly Config Discovery
3
+ *
4
+ * Finds the .opencarly/ configuration directory by:
5
+ * 1. Walking up from cwd looking for a local .opencarly/ with a manifest.json
6
+ * 2. Falling back to ~/.config/opencarly/ (global config)
7
+ */
8
+ export interface DiscoveryResult {
9
+ /** Absolute path to the .opencarly/ directory */
10
+ configPath: string;
11
+ /** Whether this is a local or global config */
12
+ scope: "local" | "global";
13
+ }
14
+ /**
15
+ * Discover the .opencarly/ configuration directory.
16
+ *
17
+ * Walks up from `startDir` looking for a `.opencarly/manifest.json`.
18
+ * Falls back to `~/.config/opencarly/manifest.json`.
19
+ * Returns null if no config found anywhere.
20
+ */
21
+ export declare function discoverConfig(startDir: string): DiscoveryResult | null;
22
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/config/discovery.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH,MAAM,WAAW,eAAe;IAC9B,iDAAiD;IACjD,UAAU,EAAE,MAAM,CAAC;IAEnB,+CAA+C;IAC/C,KAAK,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAyBvE"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * OpenCarly Config Discovery
3
+ *
4
+ * Finds the .opencarly/ configuration directory by:
5
+ * 1. Walking up from cwd looking for a local .opencarly/ with a manifest.json
6
+ * 2. Falling back to ~/.config/opencarly/ (global config)
7
+ */
8
+ import * as fs from "fs";
9
+ import * as path from "path";
10
+ import * as os from "os";
11
+ const CONFIG_DIR_NAME = ".opencarly";
12
+ const MANIFEST_FILE = "manifest.json";
13
+ const MAX_WALK_DEPTH = 10;
14
+ /**
15
+ * Discover the .opencarly/ configuration directory.
16
+ *
17
+ * Walks up from `startDir` looking for a `.opencarly/manifest.json`.
18
+ * Falls back to `~/.config/opencarly/manifest.json`.
19
+ * Returns null if no config found anywhere.
20
+ */
21
+ export function discoverConfig(startDir) {
22
+ // 1. Walk up from startDir looking for local .opencarly/
23
+ let current = path.resolve(startDir);
24
+ for (let i = 0; i < MAX_WALK_DEPTH; i++) {
25
+ const candidate = path.join(current, CONFIG_DIR_NAME);
26
+ const manifestPath = path.join(candidate, MANIFEST_FILE);
27
+ if (fs.existsSync(manifestPath)) {
28
+ return { configPath: candidate, scope: "local" };
29
+ }
30
+ const parent = path.dirname(current);
31
+ if (parent === current)
32
+ break; // reached filesystem root
33
+ current = parent;
34
+ }
35
+ // 2. Check global config
36
+ const globalConfig = path.join(os.homedir(), ".config", "opencarly");
37
+ const globalManifest = path.join(globalConfig, MANIFEST_FILE);
38
+ if (fs.existsSync(globalManifest)) {
39
+ return { configPath: globalConfig, scope: "global" };
40
+ }
41
+ return null;
42
+ }
43
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/config/discovery.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB,MAAM,eAAe,GAAG,YAAY,CAAC;AACrC,MAAM,aAAa,GAAG,eAAe,CAAC;AACtC,MAAM,cAAc,GAAG,EAAE,CAAC;AAU1B;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,yDAAyD;IACzD,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACrC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;QACtD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QAEzD,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAChC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;QACnD,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,MAAM,KAAK,OAAO;YAAE,MAAM,CAAC,0BAA0B;QACzD,OAAO,GAAG,MAAM,CAAC;IACnB,CAAC;IAED,yBAAyB;IACzB,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;IACrE,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;IAE9D,IAAI,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QAClC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;IACvD,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Config module exports
3
+ */
4
+ export { discoverConfig, type DiscoveryResult } from "./discovery";
5
+ export { loadConfig, reloadConfig, parseDomainFile, type CarlyConfig } from "./manifest";
6
+ export { ManifestSchema, DomainConfigSchema, CommandsFileSchema, StarCommandSchema, ContextFileSchema, ContextBracketSchema, TrimmingConfigSchema, StatsConfigSchema, TRIM_THRESHOLDS, TokenStatsSchema, CumulativeStatsSchema, CumulativeSessionSummarySchema, SessionConfigSchema, SessionOverrideSchema, type Manifest, type DomainConfig, type CommandsFile, type StarCommand, type ContextFile, type ContextBracket, type TrimmingConfig, type StatsConfig, type TokenStats, type CumulativeStats, type CumulativeSessionSummary, type SessionConfig, type SessionOverride, type BracketName, } from "./schema";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,eAAe,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AACzF,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,qBAAqB,EACrB,8BAA8B,EAC9B,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,wBAAwB,EAC7B,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,WAAW,GACjB,MAAM,UAAU,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Config module exports
3
+ */
4
+ export { discoverConfig } from "./discovery";
5
+ export { loadConfig, reloadConfig, parseDomainFile } from "./manifest";
6
+ export { ManifestSchema, DomainConfigSchema, CommandsFileSchema, StarCommandSchema, ContextFileSchema, ContextBracketSchema, TrimmingConfigSchema, StatsConfigSchema, TRIM_THRESHOLDS, TokenStatsSchema, CumulativeStatsSchema, CumulativeSessionSummarySchema, SessionConfigSchema, SessionOverrideSchema, } from "./schema";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAwB,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,eAAe,EAAoB,MAAM,YAAY,CAAC;AACzF,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,qBAAqB,EACrB,8BAA8B,EAC9B,mBAAmB,EACnB,qBAAqB,GAetB,MAAM,UAAU,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * OpenCarly Config Loader
3
+ *
4
+ * Parses and validates manifest.json, commands.json, and context.json
5
+ * from the discovered .opencarly/ directory.
6
+ * Collects warnings for non-fatal issues instead of silently ignoring them.
7
+ */
8
+ import { type Manifest, type CommandsFile, type ContextFile } from "./schema";
9
+ export interface CarlyConfig {
10
+ /** Parsed and validated manifest */
11
+ manifest: Manifest;
12
+ /** Parsed and validated star-commands (empty object if commands.json missing) */
13
+ commands: CommandsFile;
14
+ /** Parsed and validated context brackets (defaults if context.json missing) */
15
+ context: ContextFile;
16
+ /** Absolute path to the .opencarly/ directory */
17
+ configPath: string;
18
+ /** Non-fatal warnings encountered during config loading */
19
+ warnings: string[];
20
+ }
21
+ /**
22
+ * Load all configuration from a .opencarly/ directory.
23
+ * Validates against Zod schemas. Collects warnings for non-fatal issues.
24
+ * Throws only when manifest.json is missing entirely.
25
+ */
26
+ export declare function loadConfig(configPath: string): CarlyConfig;
27
+ /**
28
+ * Parse a domain rule file (.md).
29
+ *
30
+ * Extracts rules from bullet points (lines starting with "- ").
31
+ * Ignores headings (#), empty lines, and other markdown.
32
+ */
33
+ export declare function parseDomainFile(filePath: string): string[];
34
+ /**
35
+ * Reload config from disk. Used when config might have changed
36
+ * (e.g., user edited manifest.json via /carly command).
37
+ */
38
+ export declare function reloadConfig(configPath: string): CarlyConfig;
39
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/config/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,EAIL,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,WAAW,EACjB,MAAM,UAAU,CAAC;AAElB,MAAM,WAAW,WAAW;IAC1B,oCAAoC;IACpC,QAAQ,EAAE,QAAQ,CAAC;IAEnB,iFAAiF;IACjF,QAAQ,EAAE,YAAY,CAAC;IAEvB,+EAA+E;IAC/E,OAAO,EAAE,WAAW,CAAC;IAErB,iDAAiD;IACjD,UAAU,EAAE,MAAM,CAAC;IAEnB,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AA0BD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,CAmF1D;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAmB1D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,CAE5D"}