prepia 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 (60) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +312 -0
  3. package/bin/prepia.mjs +119 -0
  4. package/package.json +53 -0
  5. package/skill/SKILL.md +148 -0
  6. package/skill/config.json +29 -0
  7. package/src/analytics/dashboard.mjs +84 -0
  8. package/src/analytics/tracker.mjs +131 -0
  9. package/src/api/middleware.mjs +219 -0
  10. package/src/api/routes.mjs +142 -0
  11. package/src/api/server.mjs +150 -0
  12. package/src/cache/disk-store.mjs +199 -0
  13. package/src/cache/manager.mjs +142 -0
  14. package/src/cache/memory-store.mjs +205 -0
  15. package/src/chain/dag.mjs +209 -0
  16. package/src/chain/executor.mjs +103 -0
  17. package/src/chain/scheduler.mjs +89 -0
  18. package/src/client/adapters.mjs +483 -0
  19. package/src/client/connector.mjs +391 -0
  20. package/src/client/index.mjs +483 -0
  21. package/src/client/websocket.mjs +353 -0
  22. package/src/core/context-packager.mjs +169 -0
  23. package/src/core/engine.mjs +338 -0
  24. package/src/core/event-bus.mjs +84 -0
  25. package/src/core/prepimshot.mjs +120 -0
  26. package/src/core/task-decomposer.mjs +158 -0
  27. package/src/edge/lite.mjs +90 -0
  28. package/src/guard/checker.mjs +123 -0
  29. package/src/guard/fact-checker.mjs +105 -0
  30. package/src/guard/hallucination.mjs +108 -0
  31. package/src/index.mjs +67 -0
  32. package/src/models/local-model.mjs +171 -0
  33. package/src/models/provider.mjs +192 -0
  34. package/src/models/router.mjs +156 -0
  35. package/src/morph/optimizer.mjs +142 -0
  36. package/src/network/p2p.mjs +146 -0
  37. package/src/persona/detector.mjs +118 -0
  38. package/src/plugins/loader.mjs +120 -0
  39. package/src/plugins/registry.mjs +164 -0
  40. package/src/plugins/sandbox.mjs +79 -0
  41. package/src/rate/limiter.mjs +145 -0
  42. package/src/rate/shield.mjs +150 -0
  43. package/src/script/executor.mjs +164 -0
  44. package/src/script/parser.mjs +134 -0
  45. package/src/security/privacy.mjs +108 -0
  46. package/src/security/sanitizer.mjs +133 -0
  47. package/src/shadow/daemon.mjs +128 -0
  48. package/src/stream/handler.mjs +204 -0
  49. package/src/tools/calculator.mjs +312 -0
  50. package/src/tools/file-ops.mjs +138 -0
  51. package/src/tools/http-client.mjs +127 -0
  52. package/src/tools/orchestrator.mjs +205 -0
  53. package/src/tools/web-scraper.mjs +159 -0
  54. package/src/tools/web-search.mjs +129 -0
  55. package/src/vault/knowledge-base.mjs +207 -0
  56. package/src/vault/pattern-learner.mjs +192 -0
  57. package/workflows/analyze.json +32 -0
  58. package/workflows/automate.json +32 -0
  59. package/workflows/research.json +37 -0
  60. package/workflows/summarize.json +32 -0
@@ -0,0 +1,209 @@
1
+ /**
2
+ * @fileoverview DAG (Directed Acyclic Graph) for task dependencies.
3
+ * @module chain/dag
4
+ */
5
+
6
+ export class DAG {
7
+ constructor() {
8
+ /** @type {Map<string, Set<string>>} Adjacency list: node -> dependencies */
9
+ this._nodes = new Map();
10
+ /** @type {Map<string, *>} Node metadata */
11
+ this._metadata = new Map();
12
+ }
13
+
14
+ /**
15
+ * Add a node to the DAG.
16
+ * @param {string} id - Node ID
17
+ * @param {*} [metadata] - Optional metadata
18
+ */
19
+ addNode(id, metadata) {
20
+ if (!this._nodes.has(id)) {
21
+ this._nodes.set(id, new Set());
22
+ }
23
+ if (metadata !== undefined) {
24
+ this._metadata.set(id, metadata);
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Add a dependency edge (from depends on to).
30
+ * @param {string} from - Dependent node
31
+ * @param {string} to - Dependency node
32
+ */
33
+ addEdge(from, to) {
34
+ this.addNode(from);
35
+ this.addNode(to);
36
+ // Check for cycle before adding
37
+ if (this._wouldCycle(from, to)) {
38
+ throw new Error(`Adding edge ${from} -> ${to} would create a cycle`);
39
+ }
40
+ this._nodes.get(from).add(to);
41
+ }
42
+
43
+ /**
44
+ * Check if adding an edge would create a cycle.
45
+ * @param {string} from
46
+ * @param {string} to
47
+ * @returns {boolean}
48
+ * @private
49
+ */
50
+ _wouldCycle(from, to) {
51
+ if (from === to) return true;
52
+ // BFS from to to see if we can reach from
53
+ const visited = new Set();
54
+ const queue = [to];
55
+ while (queue.length > 0) {
56
+ const current = queue.shift();
57
+ if (current === from) return true;
58
+ if (visited.has(current)) continue;
59
+ visited.add(current);
60
+ const deps = this._nodes.get(current);
61
+ if (deps) {
62
+ for (const dep of deps) {
63
+ queue.push(dep);
64
+ }
65
+ }
66
+ }
67
+ return false;
68
+ }
69
+
70
+ /**
71
+ * Check if the DAG has a cycle.
72
+ * @returns {boolean}
73
+ */
74
+ hasCycle() {
75
+ const visited = new Set();
76
+ const inStack = new Set();
77
+
78
+ const dfs = (node) => {
79
+ if (inStack.has(node)) return true;
80
+ if (visited.has(node)) return false;
81
+ visited.add(node);
82
+ inStack.add(node);
83
+ const deps = this._nodes.get(node) || new Set();
84
+ for (const dep of deps) {
85
+ if (dfs(dep)) return true;
86
+ }
87
+ inStack.delete(node);
88
+ return false;
89
+ };
90
+
91
+ for (const node of this._nodes.keys()) {
92
+ if (dfs(node)) return true;
93
+ }
94
+ return false;
95
+ }
96
+
97
+ /**
98
+ * Get topological order of nodes.
99
+ * @returns {string[]} Nodes in topological order
100
+ * @throws {Error} If cycle detected
101
+ */
102
+ topologicalSort() {
103
+ const visited = new Set();
104
+ const result = [];
105
+ const inStack = new Set();
106
+
107
+ const dfs = (node) => {
108
+ if (inStack.has(node)) throw new Error('Cycle detected in DAG');
109
+ if (visited.has(node)) return;
110
+ visited.add(node);
111
+ inStack.add(node);
112
+ const deps = this._nodes.get(node) || new Set();
113
+ for (const dep of deps) {
114
+ dfs(dep);
115
+ }
116
+ inStack.delete(node);
117
+ result.push(node);
118
+ };
119
+
120
+ for (const node of this._nodes.keys()) {
121
+ dfs(node);
122
+ }
123
+
124
+ return result;
125
+ }
126
+
127
+ /**
128
+ * Get nodes with no dependencies (roots).
129
+ * @returns {string[]}
130
+ */
131
+ getRoots() {
132
+ const hasDeps = new Set();
133
+ for (const deps of this._nodes.values()) {
134
+ for (const dep of deps) {
135
+ hasDeps.add(dep);
136
+ }
137
+ }
138
+ return Array.from(this._nodes.keys()).filter(n => !hasDeps.has(n));
139
+ }
140
+
141
+ /**
142
+ * Get dependencies of a node.
143
+ * @param {string} id
144
+ * @returns {string[]}
145
+ */
146
+ getDependencies(id) {
147
+ return Array.from(this._nodes.get(id) || []);
148
+ }
149
+
150
+ /**
151
+ * Get nodes that depend on a given node.
152
+ * @param {string} id
153
+ * @returns {string[]}
154
+ */
155
+ getDependents(id) {
156
+ const result = [];
157
+ for (const [node, deps] of this._nodes) {
158
+ if (deps.has(id)) result.push(node);
159
+ }
160
+ return result;
161
+ }
162
+
163
+ /**
164
+ * Get metadata for a node.
165
+ * @param {string} id
166
+ * @returns {*}
167
+ */
168
+ getMetadata(id) {
169
+ return this._metadata.get(id);
170
+ }
171
+
172
+ /**
173
+ * Get all node IDs.
174
+ * @returns {string[]}
175
+ */
176
+ getNodes() {
177
+ return Array.from(this._nodes.keys());
178
+ }
179
+
180
+ /**
181
+ * Get the number of nodes.
182
+ * @returns {number}
183
+ */
184
+ get size() {
185
+ return this._nodes.size;
186
+ }
187
+
188
+ /**
189
+ * Remove a node and all its edges.
190
+ * @param {string} id
191
+ */
192
+ removeNode(id) {
193
+ this._nodes.delete(id);
194
+ this._metadata.delete(id);
195
+ for (const deps of this._nodes.values()) {
196
+ deps.delete(id);
197
+ }
198
+ }
199
+
200
+ /**
201
+ * Clear the entire DAG.
202
+ */
203
+ clear() {
204
+ this._nodes.clear();
205
+ this._metadata.clear();
206
+ }
207
+ }
208
+
209
+ export default DAG;
@@ -0,0 +1,103 @@
1
+ /**
2
+ * @fileoverview Task execution engine with retry support.
3
+ * @module chain/executor
4
+ */
5
+
6
+ import { EventEmitter } from 'node:events';
7
+
8
+ export class Executor extends EventEmitter {
9
+ /**
10
+ * @param {Object} [options]
11
+ * @param {number} [options.maxRetries=3] - Max retry attempts
12
+ * @param {number} [options.retryDelay=1000] - Base retry delay in ms
13
+ * @param {number} [options.timeout=30000] - Task timeout in ms
14
+ */
15
+ constructor(options = {}) {
16
+ super();
17
+ this._maxRetries = options.maxRetries ?? 3;
18
+ this._retryDelay = options.retryDelay ?? 1000;
19
+ this._timeout = options.timeout ?? 30000;
20
+ this._taskHandlers = new Map();
21
+ }
22
+
23
+ /**
24
+ * Register a task handler.
25
+ * @param {string} type - Task type
26
+ * @param {Function} handler - Async handler function(params) => result
27
+ */
28
+ register(type, handler) {
29
+ this._taskHandlers.set(type, handler);
30
+ }
31
+
32
+ /**
33
+ * Execute a single task with retries.
34
+ * @param {Object} task
35
+ * @param {string} task.id - Task ID
36
+ * @param {string} task.type - Task type
37
+ * @param {Object} [task.params] - Task parameters
38
+ * @returns {Promise<*>}
39
+ */
40
+ async execute(task) {
41
+ const handler = this._taskHandlers.get(task.type);
42
+ if (!handler) {
43
+ throw new Error(`No handler registered for task type: ${task.type}`);
44
+ }
45
+
46
+ let lastError;
47
+ for (let attempt = 0; attempt <= this._maxRetries; attempt++) {
48
+ try {
49
+ this.emit('task:attempt', { id: task.id, attempt });
50
+ const result = await Promise.race([
51
+ handler(task.params || {}),
52
+ new Promise((_, reject) =>
53
+ setTimeout(() => reject(new Error('Task timeout')), this._timeout)
54
+ ),
55
+ ]);
56
+ this.emit('task:success', { id: task.id, attempt });
57
+ return result;
58
+ } catch (err) {
59
+ lastError = err;
60
+ this.emit('task:retry', { id: task.id, attempt, error: err.message });
61
+ if (attempt < this._maxRetries) {
62
+ await new Promise(r => setTimeout(r, this._retryDelay * Math.pow(2, attempt)));
63
+ }
64
+ }
65
+ }
66
+
67
+ this.emit('task:failed', { id: task.id, error: lastError?.message });
68
+ throw new Error(`Task ${task.id} failed after ${this._maxRetries + 1} attempts: ${lastError?.message}`);
69
+ }
70
+
71
+ /**
72
+ * Execute multiple tasks in parallel.
73
+ * @param {Object[]} tasks
74
+ * @param {number} [concurrency=5]
75
+ * @returns {Promise<Map<string, *>>}
76
+ */
77
+ async executeAll(tasks, concurrency = 5) {
78
+ const results = new Map();
79
+ const executing = new Set();
80
+
81
+ for (const task of tasks) {
82
+ const promise = this.execute(task)
83
+ .then(result => {
84
+ executing.delete(promise);
85
+ results.set(task.id, result);
86
+ })
87
+ .catch(err => {
88
+ executing.delete(promise);
89
+ results.set(task.id, { error: err.message });
90
+ });
91
+ executing.add(promise);
92
+
93
+ if (executing.size >= concurrency) {
94
+ await Promise.race(executing);
95
+ }
96
+ }
97
+
98
+ await Promise.all(executing);
99
+ return results;
100
+ }
101
+ }
102
+
103
+ export default Executor;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * @fileoverview Parallel task scheduler respecting DAG dependencies.
3
+ * @module chain/scheduler
4
+ */
5
+
6
+ import { EventEmitter } from 'node:events';
7
+
8
+ export class Scheduler extends EventEmitter {
9
+ /**
10
+ * @param {Object} [options]
11
+ * @param {number} [options.maxConcurrency=5] - Max parallel tasks
12
+ */
13
+ constructor(options = {}) {
14
+ super();
15
+ this._maxConcurrency = options.maxConcurrency ?? 5;
16
+ }
17
+
18
+ /**
19
+ * Schedule and execute tasks respecting dependencies.
20
+ * @param {import('./dag.mjs').DAG} dag - Task dependency graph
21
+ * @param {Function} executor - Async function(taskId) => result
22
+ * @returns {Promise<Map<string, *>>} Results map
23
+ */
24
+ async schedule(dag, executor) {
25
+ const results = new Map();
26
+ const completed = new Set();
27
+ const failed = new Set();
28
+ const running = new Set();
29
+ const pending = new Set(dag.getNodes());
30
+
31
+ const getReady = () => {
32
+ const ready = [];
33
+ for (const nodeId of pending) {
34
+ if (running.has(nodeId) || failed.has(nodeId)) continue;
35
+ const deps = dag.getDependencies(nodeId);
36
+ const allDepsResolved = deps.every(d => completed.has(d) || failed.has(d));
37
+ const noDepsFailed = deps.every(d => !failed.has(d));
38
+ if (allDepsResolved && noDepsFailed) {
39
+ ready.push(nodeId);
40
+ }
41
+ }
42
+ return ready;
43
+ };
44
+
45
+ return new Promise((resolve) => {
46
+ const trySchedule = () => {
47
+ if (completed.size + failed.size === dag.size) {
48
+ resolve(results);
49
+ return;
50
+ }
51
+
52
+ const ready = getReady();
53
+ for (const nodeId of ready) {
54
+ if (running.size >= this._maxConcurrency) break;
55
+ if (running.has(nodeId)) continue;
56
+
57
+ running.add(nodeId);
58
+ pending.delete(nodeId);
59
+ this.emit('task:start', { nodeId });
60
+
61
+ executor(nodeId, dag.getMetadata(nodeId))
62
+ .then(result => {
63
+ results.set(nodeId, result);
64
+ completed.add(nodeId);
65
+ running.delete(nodeId);
66
+ this.emit('task:complete', { nodeId, result });
67
+ trySchedule();
68
+ })
69
+ .catch(err => {
70
+ results.set(nodeId, { error: err.message });
71
+ failed.add(nodeId);
72
+ running.delete(nodeId);
73
+ this.emit('task:error', { nodeId, error: err.message });
74
+ trySchedule();
75
+ });
76
+ }
77
+
78
+ // If nothing is running and nothing is ready, we're stuck
79
+ if (running.size === 0 && getReady().length === 0) {
80
+ resolve(results);
81
+ }
82
+ };
83
+
84
+ trySchedule();
85
+ });
86
+ }
87
+ }
88
+
89
+ export default Scheduler;