@directive-run/knowledge 0.2.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/LICENSE +21 -0
- package/README.md +63 -0
- package/ai/ai-adapters.md +250 -0
- package/ai/ai-agents-streaming.md +269 -0
- package/ai/ai-budget-resilience.md +235 -0
- package/ai/ai-communication.md +281 -0
- package/ai/ai-debug-observability.md +243 -0
- package/ai/ai-guardrails-memory.md +332 -0
- package/ai/ai-mcp-rag.md +288 -0
- package/ai/ai-multi-agent.md +274 -0
- package/ai/ai-orchestrator.md +227 -0
- package/ai/ai-security.md +293 -0
- package/ai/ai-tasks.md +261 -0
- package/ai/ai-testing-evals.md +378 -0
- package/api-skeleton.md +5 -0
- package/core/anti-patterns.md +382 -0
- package/core/constraints.md +263 -0
- package/core/core-patterns.md +228 -0
- package/core/error-boundaries.md +322 -0
- package/core/multi-module.md +315 -0
- package/core/naming.md +283 -0
- package/core/plugins.md +344 -0
- package/core/react-adapter.md +262 -0
- package/core/resolvers.md +357 -0
- package/core/schema-types.md +262 -0
- package/core/system-api.md +271 -0
- package/core/testing.md +257 -0
- package/core/time-travel.md +238 -0
- package/dist/index.cjs +111 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +102 -0
- package/dist/index.js.map +1 -0
- package/examples/ab-testing.ts +385 -0
- package/examples/ai-checkpoint.ts +509 -0
- package/examples/ai-guardrails.ts +319 -0
- package/examples/ai-orchestrator.ts +589 -0
- package/examples/async-chains.ts +287 -0
- package/examples/auth-flow.ts +371 -0
- package/examples/batch-resolver.ts +341 -0
- package/examples/checkers.ts +589 -0
- package/examples/contact-form.ts +176 -0
- package/examples/counter.ts +393 -0
- package/examples/dashboard-loader.ts +512 -0
- package/examples/debounce-constraints.ts +105 -0
- package/examples/dynamic-modules.ts +293 -0
- package/examples/error-boundaries.ts +430 -0
- package/examples/feature-flags.ts +220 -0
- package/examples/form-wizard.ts +347 -0
- package/examples/fraud-analysis.ts +663 -0
- package/examples/goal-heist.ts +341 -0
- package/examples/multi-module.ts +57 -0
- package/examples/newsletter.ts +241 -0
- package/examples/notifications.ts +210 -0
- package/examples/optimistic-updates.ts +317 -0
- package/examples/pagination.ts +260 -0
- package/examples/permissions.ts +337 -0
- package/examples/provider-routing.ts +403 -0
- package/examples/server.ts +316 -0
- package/examples/shopping-cart.ts +422 -0
- package/examples/sudoku.ts +630 -0
- package/examples/theme-locale.ts +204 -0
- package/examples/time-machine.ts +225 -0
- package/examples/topic-guard.ts +306 -0
- package/examples/url-sync.ts +333 -0
- package/examples/websocket.ts +404 -0
- package/package.json +65 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# Time-Travel Debugging
|
|
2
|
+
|
|
3
|
+
Directive can record every fact change as a snapshot, enabling undo/redo, replay, and state export for bug reports.
|
|
4
|
+
|
|
5
|
+
## Decision Tree: "Should I enable time-travel?"
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
What's the use case?
|
|
9
|
+
├── Debugging during development → Yes, enable with maxSnapshots cap
|
|
10
|
+
├── Production app → No, disable for performance
|
|
11
|
+
├── Bug reproduction → Enable, use exportHistory() to share
|
|
12
|
+
├── Testing → Usually no — use assertFact/assertDerivation instead
|
|
13
|
+
└── Demo / presentation → Yes, great for showing state changes
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Enabling Time-Travel
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { createSystem } from "@directive-run/core";
|
|
20
|
+
|
|
21
|
+
const system = createSystem({
|
|
22
|
+
module: myModule,
|
|
23
|
+
debug: {
|
|
24
|
+
timeTravel: true, // Enable snapshot recording
|
|
25
|
+
maxSnapshots: 100, // Cap memory usage (default: 50)
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Time-travel is disabled by default. Snapshots are recorded automatically on every fact mutation.
|
|
31
|
+
|
|
32
|
+
## The TimeTravelAPI
|
|
33
|
+
|
|
34
|
+
Access via `system.debug.timeTravel`:
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
const tt = system.debug.timeTravel;
|
|
38
|
+
|
|
39
|
+
// Navigation
|
|
40
|
+
tt.canUndo(); // boolean — is there a previous snapshot?
|
|
41
|
+
tt.canRedo(); // boolean — is there a next snapshot?
|
|
42
|
+
tt.undo(); // Restore previous snapshot
|
|
43
|
+
tt.redo(); // Restore next snapshot
|
|
44
|
+
|
|
45
|
+
// Direct access
|
|
46
|
+
tt.getSnapshots(); // Array of all snapshots
|
|
47
|
+
tt.goToSnapshot(index); // Jump to a specific snapshot by index
|
|
48
|
+
|
|
49
|
+
// Each snapshot contains:
|
|
50
|
+
// {
|
|
51
|
+
// facts: { ... }, — full fact state at that point
|
|
52
|
+
// timestamp: number, — when the snapshot was taken
|
|
53
|
+
// label?: string, — optional label from changeset
|
|
54
|
+
// changedKeys: string[], — which facts changed
|
|
55
|
+
// }
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Undo/Redo Pattern
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
const system = createSystem({
|
|
62
|
+
module: editorModule,
|
|
63
|
+
debug: { timeTravel: true, maxSnapshots: 200 },
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
system.start();
|
|
67
|
+
|
|
68
|
+
// User makes changes
|
|
69
|
+
system.facts.text = "Hello";
|
|
70
|
+
system.facts.text = "Hello, world";
|
|
71
|
+
system.facts.text = "Hello, world!";
|
|
72
|
+
|
|
73
|
+
// Undo last change
|
|
74
|
+
const tt = system.debug.timeTravel;
|
|
75
|
+
tt.undo();
|
|
76
|
+
console.log(system.facts.text); // "Hello, world"
|
|
77
|
+
|
|
78
|
+
tt.undo();
|
|
79
|
+
console.log(system.facts.text); // "Hello"
|
|
80
|
+
|
|
81
|
+
// Redo
|
|
82
|
+
tt.redo();
|
|
83
|
+
console.log(system.facts.text); // "Hello, world"
|
|
84
|
+
|
|
85
|
+
// Check navigation state
|
|
86
|
+
tt.canUndo(); // true
|
|
87
|
+
tt.canRedo(); // true
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Changesets: Grouping Related Changes
|
|
91
|
+
|
|
92
|
+
Multiple fact mutations can be grouped into a single undoable unit.
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
const tt = system.debug.timeTravel;
|
|
96
|
+
|
|
97
|
+
// Without changeset — each mutation is a separate snapshot
|
|
98
|
+
system.facts.firstName = "Alice";
|
|
99
|
+
system.facts.lastName = "Smith";
|
|
100
|
+
// Two snapshots, two undos needed
|
|
101
|
+
|
|
102
|
+
// With changeset — grouped into one snapshot
|
|
103
|
+
tt.beginChangeset("Update user name");
|
|
104
|
+
system.facts.firstName = "Alice";
|
|
105
|
+
system.facts.lastName = "Smith";
|
|
106
|
+
tt.endChangeset();
|
|
107
|
+
// One snapshot, one undo restores both
|
|
108
|
+
|
|
109
|
+
// Undo reverts the entire changeset
|
|
110
|
+
tt.undo();
|
|
111
|
+
// Both firstName and lastName are restored
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Use changesets for logically related mutations: form submissions, multi-field updates, resolver results.
|
|
115
|
+
|
|
116
|
+
## Exporting and Importing History
|
|
117
|
+
|
|
118
|
+
Serialize the full snapshot history for bug reports or debugging.
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
const tt = system.debug.timeTravel;
|
|
122
|
+
|
|
123
|
+
// Export — returns a serializable object
|
|
124
|
+
const historyData = tt.exportHistory();
|
|
125
|
+
// Send to server, save to file, attach to bug report
|
|
126
|
+
console.log(JSON.stringify(historyData));
|
|
127
|
+
|
|
128
|
+
// Import — restore history from exported data
|
|
129
|
+
tt.importHistory(historyData);
|
|
130
|
+
|
|
131
|
+
// Now you can step through the user's exact state sequence
|
|
132
|
+
tt.goToSnapshot(0); // Start
|
|
133
|
+
tt.goToSnapshot(5); // When the bug occurred
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Snapshot Inspection
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
const tt = system.debug.timeTravel;
|
|
140
|
+
const snapshots = tt.getSnapshots();
|
|
141
|
+
|
|
142
|
+
// Walk through all snapshots
|
|
143
|
+
for (const snap of snapshots) {
|
|
144
|
+
console.log(`[${new Date(snap.timestamp).toISOString()}]`);
|
|
145
|
+
console.log(` Changed: ${snap.changedKeys.join(", ")}`);
|
|
146
|
+
if (snap.label) {
|
|
147
|
+
console.log(` Label: ${snap.label}`);
|
|
148
|
+
}
|
|
149
|
+
console.log(` Facts:`, snap.facts);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Jump to a specific point
|
|
153
|
+
tt.goToSnapshot(3);
|
|
154
|
+
console.log(system.facts); // State as of snapshot 3
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Performance: maxSnapshots
|
|
158
|
+
|
|
159
|
+
Every fact mutation creates a snapshot. Cap the number to control memory:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
// Low memory — keeps last 20 snapshots, discards oldest
|
|
163
|
+
debug: { timeTravel: true, maxSnapshots: 20 },
|
|
164
|
+
|
|
165
|
+
// Development — generous cap for deep debugging
|
|
166
|
+
debug: { timeTravel: true, maxSnapshots: 500 },
|
|
167
|
+
|
|
168
|
+
// Default if not specified
|
|
169
|
+
debug: { timeTravel: true }, // maxSnapshots defaults to 50
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
When the cap is reached, the oldest snapshot is discarded (FIFO). Redo history beyond the cap is lost.
|
|
173
|
+
|
|
174
|
+
## Common Mistakes
|
|
175
|
+
|
|
176
|
+
### Enabling time-travel in production
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
// WRONG — snapshots consume memory on every mutation
|
|
180
|
+
const system = createSystem({
|
|
181
|
+
module: myModule,
|
|
182
|
+
debug: { timeTravel: true },
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// CORRECT — gate on environment
|
|
186
|
+
const system = createSystem({
|
|
187
|
+
module: myModule,
|
|
188
|
+
debug: {
|
|
189
|
+
timeTravel: process.env.NODE_ENV === "development",
|
|
190
|
+
maxSnapshots: 100,
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Forgetting to end a changeset
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
// WRONG — changeset never closed, all subsequent mutations are grouped
|
|
199
|
+
tt.beginChangeset("update");
|
|
200
|
+
system.facts.name = "Alice";
|
|
201
|
+
// ... forgot endChangeset()
|
|
202
|
+
system.facts.unrelated = true; // Still part of the changeset!
|
|
203
|
+
|
|
204
|
+
// CORRECT — always close changesets
|
|
205
|
+
tt.beginChangeset("update");
|
|
206
|
+
system.facts.name = "Alice";
|
|
207
|
+
tt.endChangeset();
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Accessing time-travel when disabled
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
// WRONG — timeTravel not enabled, system.debug.timeTravel is null
|
|
214
|
+
const system = createSystem({ module: myModule });
|
|
215
|
+
system.debug.timeTravel.undo(); // TypeError!
|
|
216
|
+
|
|
217
|
+
// CORRECT — check before using
|
|
218
|
+
const tt = system.debug.timeTravel;
|
|
219
|
+
if (tt) {
|
|
220
|
+
tt.undo();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Or enable it
|
|
224
|
+
const system = createSystem({
|
|
225
|
+
module: myModule,
|
|
226
|
+
debug: { timeTravel: true },
|
|
227
|
+
});
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### No maxSnapshots cap with frequent mutations
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
// WRONG — unbounded snapshots in a high-frequency update loop
|
|
234
|
+
debug: { timeTravel: true }, // Default cap is 50, which is fine
|
|
235
|
+
|
|
236
|
+
// Be explicit when mutation rate is high
|
|
237
|
+
debug: { timeTravel: true, maxSnapshots: 30 },
|
|
238
|
+
```
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fs = require('fs');
|
|
4
|
+
var path = require('path');
|
|
5
|
+
var url = require('url');
|
|
6
|
+
|
|
7
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
8
|
+
// src/index.ts
|
|
9
|
+
var __dirname$1 = path.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))));
|
|
10
|
+
var PKG_ROOT = path.resolve(__dirname$1, "..");
|
|
11
|
+
function resolveAsset(name) {
|
|
12
|
+
const fromDist = path.join(PKG_ROOT, name);
|
|
13
|
+
if (fs.existsSync(fromDist)) {
|
|
14
|
+
return fromDist;
|
|
15
|
+
}
|
|
16
|
+
const fromSrc = path.join(PKG_ROOT, "..", name);
|
|
17
|
+
if (fs.existsSync(fromSrc)) {
|
|
18
|
+
return fromSrc;
|
|
19
|
+
}
|
|
20
|
+
return fromDist;
|
|
21
|
+
}
|
|
22
|
+
var CORE_DIR = resolveAsset("core");
|
|
23
|
+
var AI_DIR = resolveAsset("ai");
|
|
24
|
+
var EXAMPLES_DIR = resolveAsset("examples");
|
|
25
|
+
var API_SKELETON_PATH = resolveAsset("api-skeleton.md");
|
|
26
|
+
var knowledgeCache = null;
|
|
27
|
+
var exampleCache = null;
|
|
28
|
+
function loadDir(dir, map) {
|
|
29
|
+
try {
|
|
30
|
+
const files = fs.readdirSync(dir).filter(
|
|
31
|
+
(f) => f.endsWith(".md") || f.endsWith(".ts")
|
|
32
|
+
);
|
|
33
|
+
for (const file of files) {
|
|
34
|
+
const name = file.replace(/\.(md|ts)$/, "");
|
|
35
|
+
map.set(name, fs.readFileSync(path.join(dir, file), "utf-8"));
|
|
36
|
+
}
|
|
37
|
+
} catch (err) {
|
|
38
|
+
if (err.code !== "ENOENT") {
|
|
39
|
+
throw err;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function loadAllKnowledge() {
|
|
44
|
+
const map = /* @__PURE__ */ new Map();
|
|
45
|
+
loadDir(CORE_DIR, map);
|
|
46
|
+
loadDir(AI_DIR, map);
|
|
47
|
+
try {
|
|
48
|
+
map.set("api-skeleton", fs.readFileSync(API_SKELETON_PATH, "utf-8"));
|
|
49
|
+
} catch {
|
|
50
|
+
}
|
|
51
|
+
return map;
|
|
52
|
+
}
|
|
53
|
+
function loadAllExamples() {
|
|
54
|
+
const map = /* @__PURE__ */ new Map();
|
|
55
|
+
loadDir(EXAMPLES_DIR, map);
|
|
56
|
+
return map;
|
|
57
|
+
}
|
|
58
|
+
function getKnowledge(name) {
|
|
59
|
+
if (!knowledgeCache) {
|
|
60
|
+
knowledgeCache = loadAllKnowledge();
|
|
61
|
+
}
|
|
62
|
+
return knowledgeCache.get(name) ?? "";
|
|
63
|
+
}
|
|
64
|
+
function getAllKnowledge() {
|
|
65
|
+
if (!knowledgeCache) {
|
|
66
|
+
knowledgeCache = loadAllKnowledge();
|
|
67
|
+
}
|
|
68
|
+
return knowledgeCache;
|
|
69
|
+
}
|
|
70
|
+
function getExample(name) {
|
|
71
|
+
if (!exampleCache) {
|
|
72
|
+
exampleCache = loadAllExamples();
|
|
73
|
+
}
|
|
74
|
+
return exampleCache.get(name) ?? "";
|
|
75
|
+
}
|
|
76
|
+
function getAllExamples() {
|
|
77
|
+
if (!exampleCache) {
|
|
78
|
+
exampleCache = loadAllExamples();
|
|
79
|
+
}
|
|
80
|
+
return exampleCache;
|
|
81
|
+
}
|
|
82
|
+
function getKnowledgeFiles(names) {
|
|
83
|
+
return names.map((name) => getKnowledge(name)).filter(Boolean).join("\n\n---\n\n");
|
|
84
|
+
}
|
|
85
|
+
function getExampleFiles(names) {
|
|
86
|
+
return names.map((name) => {
|
|
87
|
+
const content = getExample(name);
|
|
88
|
+
if (!content) {
|
|
89
|
+
return "";
|
|
90
|
+
}
|
|
91
|
+
return `### Example: ${name}
|
|
92
|
+
|
|
93
|
+
\`\`\`typescript
|
|
94
|
+
${content}
|
|
95
|
+
\`\`\``;
|
|
96
|
+
}).filter(Boolean).join("\n\n");
|
|
97
|
+
}
|
|
98
|
+
function clearCache() {
|
|
99
|
+
knowledgeCache = null;
|
|
100
|
+
exampleCache = null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
exports.clearCache = clearCache;
|
|
104
|
+
exports.getAllExamples = getAllExamples;
|
|
105
|
+
exports.getAllKnowledge = getAllKnowledge;
|
|
106
|
+
exports.getExample = getExample;
|
|
107
|
+
exports.getExampleFiles = getExampleFiles;
|
|
108
|
+
exports.getKnowledge = getKnowledge;
|
|
109
|
+
exports.getKnowledgeFiles = getKnowledgeFiles;
|
|
110
|
+
//# sourceMappingURL=index.cjs.map
|
|
111
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["__dirname","dirname","fileURLToPath","resolve","join","existsSync","readdirSync","readFileSync"],"mappings":"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","file":"index.cjs","sourcesContent":["import { existsSync, readFileSync, readdirSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n// Resolve package root: works both in src/ (dev) and dist/ (bundled)\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\n/**\n * Resolve a path relative to the package root.\n * Tries dist-relative first (bundled), then src-relative (dev).\n */\nfunction resolveAsset(name: string): string {\n const fromDist = join(PKG_ROOT, name);\n if (existsSync(fromDist)) {\n return fromDist;\n }\n\n const fromSrc = join(PKG_ROOT, \"..\", name);\n if (existsSync(fromSrc)) {\n return fromSrc;\n }\n\n return fromDist; // default, will just return empty maps\n}\n\nconst CORE_DIR = resolveAsset(\"core\");\nconst AI_DIR = resolveAsset(\"ai\");\nconst EXAMPLES_DIR = resolveAsset(\"examples\");\nconst API_SKELETON_PATH = resolveAsset(\"api-skeleton.md\");\n\nlet knowledgeCache: Map<string, string> | null = null;\nlet exampleCache: Map<string, string> | null = null;\n\nfunction loadDir(dir: string, map: Map<string, string>): void {\n try {\n const files = readdirSync(dir).filter(\n (f) => f.endsWith(\".md\") || f.endsWith(\".ts\"),\n );\n for (const file of files) {\n const name = file.replace(/\\.(md|ts)$/, \"\");\n map.set(name, readFileSync(join(dir, file), \"utf-8\"));\n }\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw err;\n }\n // directory does not exist — expected during tests or incomplete installs\n }\n}\n\nfunction loadAllKnowledge(): Map<string, string> {\n const map = new Map<string, string>();\n loadDir(CORE_DIR, map);\n loadDir(AI_DIR, map);\n\n // Include api-skeleton\n try {\n map.set(\"api-skeleton\", readFileSync(API_SKELETON_PATH, \"utf-8\"));\n } catch {\n // may not exist yet\n }\n\n return map;\n}\n\nfunction loadAllExamples(): Map<string, string> {\n const map = new Map<string, string>();\n loadDir(EXAMPLES_DIR, map);\n\n return map;\n}\n\nexport function getKnowledge(name: string): string {\n if (!knowledgeCache) {\n knowledgeCache = loadAllKnowledge();\n }\n\n return knowledgeCache.get(name) ?? \"\";\n}\n\nexport function getAllKnowledge(): ReadonlyMap<string, string> {\n if (!knowledgeCache) {\n knowledgeCache = loadAllKnowledge();\n }\n\n return knowledgeCache;\n}\n\nexport function getExample(name: string): string {\n if (!exampleCache) {\n exampleCache = loadAllExamples();\n }\n\n return exampleCache.get(name) ?? \"\";\n}\n\nexport function getAllExamples(): ReadonlyMap<string, string> {\n if (!exampleCache) {\n exampleCache = loadAllExamples();\n }\n\n return exampleCache;\n}\n\nexport function getKnowledgeFiles(names: string[]): string {\n return names\n .map((name) => getKnowledge(name))\n .filter(Boolean)\n .join(\"\\n\\n---\\n\\n\");\n}\n\nexport function getExampleFiles(names: string[]): string {\n return names\n .map((name) => {\n const content = getExample(name);\n if (!content) {\n return \"\";\n }\n\n return `### Example: ${name}\\n\\n\\`\\`\\`typescript\\n${content}\\n\\`\\`\\``;\n })\n .filter(Boolean)\n .join(\"\\n\\n\");\n}\n\n/** Clear cached knowledge and examples. Useful for dev/watch mode. */\nexport function clearCache(): void {\n knowledgeCache = null;\n exampleCache = null;\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
declare function getKnowledge(name: string): string;
|
|
2
|
+
declare function getAllKnowledge(): ReadonlyMap<string, string>;
|
|
3
|
+
declare function getExample(name: string): string;
|
|
4
|
+
declare function getAllExamples(): ReadonlyMap<string, string>;
|
|
5
|
+
declare function getKnowledgeFiles(names: string[]): string;
|
|
6
|
+
declare function getExampleFiles(names: string[]): string;
|
|
7
|
+
/** Clear cached knowledge and examples. Useful for dev/watch mode. */
|
|
8
|
+
declare function clearCache(): void;
|
|
9
|
+
|
|
10
|
+
export { clearCache, getAllExamples, getAllKnowledge, getExample, getExampleFiles, getKnowledge, getKnowledgeFiles };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
declare function getKnowledge(name: string): string;
|
|
2
|
+
declare function getAllKnowledge(): ReadonlyMap<string, string>;
|
|
3
|
+
declare function getExample(name: string): string;
|
|
4
|
+
declare function getAllExamples(): ReadonlyMap<string, string>;
|
|
5
|
+
declare function getKnowledgeFiles(names: string[]): string;
|
|
6
|
+
declare function getExampleFiles(names: string[]): string;
|
|
7
|
+
/** Clear cached knowledge and examples. Useful for dev/watch mode. */
|
|
8
|
+
declare function clearCache(): void;
|
|
9
|
+
|
|
10
|
+
export { clearCache, getAllExamples, getAllKnowledge, getExample, getExampleFiles, getKnowledge, getKnowledgeFiles };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync } from 'fs';
|
|
2
|
+
import { dirname, resolve, join } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
|
|
5
|
+
// src/index.ts
|
|
6
|
+
var __dirname$1 = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
var PKG_ROOT = resolve(__dirname$1, "..");
|
|
8
|
+
function resolveAsset(name) {
|
|
9
|
+
const fromDist = join(PKG_ROOT, name);
|
|
10
|
+
if (existsSync(fromDist)) {
|
|
11
|
+
return fromDist;
|
|
12
|
+
}
|
|
13
|
+
const fromSrc = join(PKG_ROOT, "..", name);
|
|
14
|
+
if (existsSync(fromSrc)) {
|
|
15
|
+
return fromSrc;
|
|
16
|
+
}
|
|
17
|
+
return fromDist;
|
|
18
|
+
}
|
|
19
|
+
var CORE_DIR = resolveAsset("core");
|
|
20
|
+
var AI_DIR = resolveAsset("ai");
|
|
21
|
+
var EXAMPLES_DIR = resolveAsset("examples");
|
|
22
|
+
var API_SKELETON_PATH = resolveAsset("api-skeleton.md");
|
|
23
|
+
var knowledgeCache = null;
|
|
24
|
+
var exampleCache = null;
|
|
25
|
+
function loadDir(dir, map) {
|
|
26
|
+
try {
|
|
27
|
+
const files = readdirSync(dir).filter(
|
|
28
|
+
(f) => f.endsWith(".md") || f.endsWith(".ts")
|
|
29
|
+
);
|
|
30
|
+
for (const file of files) {
|
|
31
|
+
const name = file.replace(/\.(md|ts)$/, "");
|
|
32
|
+
map.set(name, readFileSync(join(dir, file), "utf-8"));
|
|
33
|
+
}
|
|
34
|
+
} catch (err) {
|
|
35
|
+
if (err.code !== "ENOENT") {
|
|
36
|
+
throw err;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function loadAllKnowledge() {
|
|
41
|
+
const map = /* @__PURE__ */ new Map();
|
|
42
|
+
loadDir(CORE_DIR, map);
|
|
43
|
+
loadDir(AI_DIR, map);
|
|
44
|
+
try {
|
|
45
|
+
map.set("api-skeleton", readFileSync(API_SKELETON_PATH, "utf-8"));
|
|
46
|
+
} catch {
|
|
47
|
+
}
|
|
48
|
+
return map;
|
|
49
|
+
}
|
|
50
|
+
function loadAllExamples() {
|
|
51
|
+
const map = /* @__PURE__ */ new Map();
|
|
52
|
+
loadDir(EXAMPLES_DIR, map);
|
|
53
|
+
return map;
|
|
54
|
+
}
|
|
55
|
+
function getKnowledge(name) {
|
|
56
|
+
if (!knowledgeCache) {
|
|
57
|
+
knowledgeCache = loadAllKnowledge();
|
|
58
|
+
}
|
|
59
|
+
return knowledgeCache.get(name) ?? "";
|
|
60
|
+
}
|
|
61
|
+
function getAllKnowledge() {
|
|
62
|
+
if (!knowledgeCache) {
|
|
63
|
+
knowledgeCache = loadAllKnowledge();
|
|
64
|
+
}
|
|
65
|
+
return knowledgeCache;
|
|
66
|
+
}
|
|
67
|
+
function getExample(name) {
|
|
68
|
+
if (!exampleCache) {
|
|
69
|
+
exampleCache = loadAllExamples();
|
|
70
|
+
}
|
|
71
|
+
return exampleCache.get(name) ?? "";
|
|
72
|
+
}
|
|
73
|
+
function getAllExamples() {
|
|
74
|
+
if (!exampleCache) {
|
|
75
|
+
exampleCache = loadAllExamples();
|
|
76
|
+
}
|
|
77
|
+
return exampleCache;
|
|
78
|
+
}
|
|
79
|
+
function getKnowledgeFiles(names) {
|
|
80
|
+
return names.map((name) => getKnowledge(name)).filter(Boolean).join("\n\n---\n\n");
|
|
81
|
+
}
|
|
82
|
+
function getExampleFiles(names) {
|
|
83
|
+
return names.map((name) => {
|
|
84
|
+
const content = getExample(name);
|
|
85
|
+
if (!content) {
|
|
86
|
+
return "";
|
|
87
|
+
}
|
|
88
|
+
return `### Example: ${name}
|
|
89
|
+
|
|
90
|
+
\`\`\`typescript
|
|
91
|
+
${content}
|
|
92
|
+
\`\`\``;
|
|
93
|
+
}).filter(Boolean).join("\n\n");
|
|
94
|
+
}
|
|
95
|
+
function clearCache() {
|
|
96
|
+
knowledgeCache = null;
|
|
97
|
+
exampleCache = null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export { clearCache, getAllExamples, getAllKnowledge, getExample, getExampleFiles, getKnowledge, getKnowledgeFiles };
|
|
101
|
+
//# sourceMappingURL=index.js.map
|
|
102
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":["__dirname"],"mappings":"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","file":"index.js","sourcesContent":["import { existsSync, readFileSync, readdirSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n// Resolve package root: works both in src/ (dev) and dist/ (bundled)\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst PKG_ROOT = resolve(__dirname, \"..\");\n\n/**\n * Resolve a path relative to the package root.\n * Tries dist-relative first (bundled), then src-relative (dev).\n */\nfunction resolveAsset(name: string): string {\n const fromDist = join(PKG_ROOT, name);\n if (existsSync(fromDist)) {\n return fromDist;\n }\n\n const fromSrc = join(PKG_ROOT, \"..\", name);\n if (existsSync(fromSrc)) {\n return fromSrc;\n }\n\n return fromDist; // default, will just return empty maps\n}\n\nconst CORE_DIR = resolveAsset(\"core\");\nconst AI_DIR = resolveAsset(\"ai\");\nconst EXAMPLES_DIR = resolveAsset(\"examples\");\nconst API_SKELETON_PATH = resolveAsset(\"api-skeleton.md\");\n\nlet knowledgeCache: Map<string, string> | null = null;\nlet exampleCache: Map<string, string> | null = null;\n\nfunction loadDir(dir: string, map: Map<string, string>): void {\n try {\n const files = readdirSync(dir).filter(\n (f) => f.endsWith(\".md\") || f.endsWith(\".ts\"),\n );\n for (const file of files) {\n const name = file.replace(/\\.(md|ts)$/, \"\");\n map.set(name, readFileSync(join(dir, file), \"utf-8\"));\n }\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException).code !== \"ENOENT\") {\n throw err;\n }\n // directory does not exist — expected during tests or incomplete installs\n }\n}\n\nfunction loadAllKnowledge(): Map<string, string> {\n const map = new Map<string, string>();\n loadDir(CORE_DIR, map);\n loadDir(AI_DIR, map);\n\n // Include api-skeleton\n try {\n map.set(\"api-skeleton\", readFileSync(API_SKELETON_PATH, \"utf-8\"));\n } catch {\n // may not exist yet\n }\n\n return map;\n}\n\nfunction loadAllExamples(): Map<string, string> {\n const map = new Map<string, string>();\n loadDir(EXAMPLES_DIR, map);\n\n return map;\n}\n\nexport function getKnowledge(name: string): string {\n if (!knowledgeCache) {\n knowledgeCache = loadAllKnowledge();\n }\n\n return knowledgeCache.get(name) ?? \"\";\n}\n\nexport function getAllKnowledge(): ReadonlyMap<string, string> {\n if (!knowledgeCache) {\n knowledgeCache = loadAllKnowledge();\n }\n\n return knowledgeCache;\n}\n\nexport function getExample(name: string): string {\n if (!exampleCache) {\n exampleCache = loadAllExamples();\n }\n\n return exampleCache.get(name) ?? \"\";\n}\n\nexport function getAllExamples(): ReadonlyMap<string, string> {\n if (!exampleCache) {\n exampleCache = loadAllExamples();\n }\n\n return exampleCache;\n}\n\nexport function getKnowledgeFiles(names: string[]): string {\n return names\n .map((name) => getKnowledge(name))\n .filter(Boolean)\n .join(\"\\n\\n---\\n\\n\");\n}\n\nexport function getExampleFiles(names: string[]): string {\n return names\n .map((name) => {\n const content = getExample(name);\n if (!content) {\n return \"\";\n }\n\n return `### Example: ${name}\\n\\n\\`\\`\\`typescript\\n${content}\\n\\`\\`\\``;\n })\n .filter(Boolean)\n .join(\"\\n\\n\");\n}\n\n/** Clear cached knowledge and examples. Useful for dev/watch mode. */\nexport function clearCache(): void {\n knowledgeCache = null;\n exampleCache = null;\n}\n"]}
|