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.
- package/README.md +78 -0
- package/bin/install.js +304 -0
- package/commands/carly-manager.md +69 -0
- package/dist/config/discovery.d.ts +22 -0
- package/dist/config/discovery.d.ts.map +1 -0
- package/dist/config/discovery.js +43 -0
- package/dist/config/discovery.js.map +1 -0
- package/dist/config/index.d.ts +7 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +7 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/manifest.d.ts +39 -0
- package/dist/config/manifest.d.ts.map +1 -0
- package/dist/config/manifest.js +139 -0
- package/dist/config/manifest.js.map +1 -0
- package/dist/config/schema.d.ts +663 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +208 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/engine/brackets.d.ts +26 -0
- package/dist/engine/brackets.d.ts.map +1 -0
- package/dist/engine/brackets.js +49 -0
- package/dist/engine/brackets.js.map +1 -0
- package/dist/engine/index.d.ts +8 -0
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/engine/index.js +8 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/engine/loader.d.ts +82 -0
- package/dist/engine/loader.d.ts.map +1 -0
- package/dist/engine/loader.js +147 -0
- package/dist/engine/loader.js.map +1 -0
- package/dist/engine/matcher.d.ts +43 -0
- package/dist/engine/matcher.d.ts.map +1 -0
- package/dist/engine/matcher.js +174 -0
- package/dist/engine/matcher.js.map +1 -0
- package/dist/engine/trimmer.d.ts +91 -0
- package/dist/engine/trimmer.d.ts.map +1 -0
- package/dist/engine/trimmer.js +236 -0
- package/dist/engine/trimmer.js.map +1 -0
- package/dist/formatter/formatter.d.ts +23 -0
- package/dist/formatter/formatter.d.ts.map +1 -0
- package/dist/formatter/formatter.js +129 -0
- package/dist/formatter/formatter.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +484 -0
- package/dist/index.js.map +1 -0
- package/dist/session/session.d.ts +60 -0
- package/dist/session/session.d.ts.map +1 -0
- package/dist/session/session.js +394 -0
- package/dist/session/session.js.map +1 -0
- package/package.json +59 -0
- package/templates/.opencarly/commands.json +96 -0
- package/templates/.opencarly/context.json +44 -0
- package/templates/.opencarly/domains/development.md +13 -0
- package/templates/.opencarly/domains/global.md +13 -0
- package/templates/.opencarly/domains/security.md +14 -0
- package/templates/.opencarly/domains/testing.md +12 -0
- 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"}
|