aiden-runtime 3.16.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 (159) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +465 -0
  3. package/config/devos.config.json +186 -0
  4. package/config/hardware.json +9 -0
  5. package/config/model-selection.json +7 -0
  6. package/config/setup-complete.json +20 -0
  7. package/dist/api/routes/computerUse.js +112 -0
  8. package/dist/api/server.js +6870 -0
  9. package/dist/bin/npx-init.js +71 -0
  10. package/dist/coordination/commandGate.js +115 -0
  11. package/dist/coordination/livePulse.js +127 -0
  12. package/dist/core/agentLoop.js +2718 -0
  13. package/dist/core/agentShield.js +231 -0
  14. package/dist/core/aidenIdentity.js +215 -0
  15. package/dist/core/aidenPersonality.js +166 -0
  16. package/dist/core/aidenSdk.js +374 -0
  17. package/dist/core/asyncTasks.js +82 -0
  18. package/dist/core/auditTrail.js +61 -0
  19. package/dist/core/auxiliaryClient.js +114 -0
  20. package/dist/core/bgLLM.js +108 -0
  21. package/dist/core/bm25.js +68 -0
  22. package/dist/core/callbackSystem.js +64 -0
  23. package/dist/core/channels/adapter.js +6 -0
  24. package/dist/core/channels/discord.js +173 -0
  25. package/dist/core/channels/email.js +253 -0
  26. package/dist/core/channels/imessage.js +164 -0
  27. package/dist/core/channels/manager.js +96 -0
  28. package/dist/core/channels/signal.js +140 -0
  29. package/dist/core/channels/slack.js +139 -0
  30. package/dist/core/channels/twilio.js +144 -0
  31. package/dist/core/channels/webhook.js +186 -0
  32. package/dist/core/channels/whatsapp.js +185 -0
  33. package/dist/core/clarifyBus.js +75 -0
  34. package/dist/core/codeInterpreter.js +82 -0
  35. package/dist/core/computerControl.js +439 -0
  36. package/dist/core/conversationMemory.js +334 -0
  37. package/dist/core/costTracker.js +221 -0
  38. package/dist/core/cronManager.js +217 -0
  39. package/dist/core/deepKB.js +77 -0
  40. package/dist/core/doctor.js +279 -0
  41. package/dist/core/dreamEngine.js +334 -0
  42. package/dist/core/entityGraph.js +169 -0
  43. package/dist/core/eventBus.js +16 -0
  44. package/dist/core/evolutionAnalyzer.js +153 -0
  45. package/dist/core/executionLoop.js +309 -0
  46. package/dist/core/executor.js +224 -0
  47. package/dist/core/failureAnalyzer.js +166 -0
  48. package/dist/core/fastPathExpansion.js +82 -0
  49. package/dist/core/faultEngine.js +106 -0
  50. package/dist/core/featureGates.js +70 -0
  51. package/dist/core/fileIngestion.js +113 -0
  52. package/dist/core/gateway.js +97 -0
  53. package/dist/core/goalTracker.js +75 -0
  54. package/dist/core/growthEngine.js +168 -0
  55. package/dist/core/hardwareDetector.js +98 -0
  56. package/dist/core/hooks.js +45 -0
  57. package/dist/core/httpKeepalive.js +46 -0
  58. package/dist/core/hybridSearch.js +101 -0
  59. package/dist/core/importers.js +164 -0
  60. package/dist/core/instinctSystem.js +223 -0
  61. package/dist/core/knowledgeBase.js +351 -0
  62. package/dist/core/learningMemory.js +121 -0
  63. package/dist/core/lessonsBrowser.js +125 -0
  64. package/dist/core/licenseManager.js +399 -0
  65. package/dist/core/logBuffer.js +85 -0
  66. package/dist/core/machineId.js +87 -0
  67. package/dist/core/mcpClient.js +442 -0
  68. package/dist/core/memoryDistiller.js +165 -0
  69. package/dist/core/memoryExtractor.js +212 -0
  70. package/dist/core/memoryIds.js +213 -0
  71. package/dist/core/memoryPreamble.js +113 -0
  72. package/dist/core/memoryQuery.js +136 -0
  73. package/dist/core/memoryRecall.js +140 -0
  74. package/dist/core/memoryStrategy.js +201 -0
  75. package/dist/core/messageValidator.js +85 -0
  76. package/dist/core/modelDiscovery.js +108 -0
  77. package/dist/core/modelRouter.js +118 -0
  78. package/dist/core/morningBriefing.js +203 -0
  79. package/dist/core/multiGoalValidator.js +51 -0
  80. package/dist/core/parallelExecutor.js +43 -0
  81. package/dist/core/passiveSkillObserver.js +204 -0
  82. package/dist/core/paths.js +57 -0
  83. package/dist/core/patternDetector.js +83 -0
  84. package/dist/core/planResponseRepair.js +64 -0
  85. package/dist/core/planTool.js +111 -0
  86. package/dist/core/playwrightBridge.js +356 -0
  87. package/dist/core/pluginSystem.js +121 -0
  88. package/dist/core/privateMode.js +85 -0
  89. package/dist/core/reactLoop.js +156 -0
  90. package/dist/core/recipeEngine.js +166 -0
  91. package/dist/core/responseCache.js +128 -0
  92. package/dist/core/runSandbox.js +132 -0
  93. package/dist/core/sandboxRunner.js +200 -0
  94. package/dist/core/scheduler.js +543 -0
  95. package/dist/core/secretScanner.js +49 -0
  96. package/dist/core/semanticMemory.js +223 -0
  97. package/dist/core/sessionMemory.js +259 -0
  98. package/dist/core/sessionRouter.js +91 -0
  99. package/dist/core/sessionSearch.js +163 -0
  100. package/dist/core/setupWizard.js +225 -0
  101. package/dist/core/skillImporter.js +303 -0
  102. package/dist/core/skillLibrary.js +144 -0
  103. package/dist/core/skillLoader.js +471 -0
  104. package/dist/core/skillTeacher.js +352 -0
  105. package/dist/core/skillValidator.js +210 -0
  106. package/dist/core/skillWriter.js +384 -0
  107. package/dist/core/slashAsTool.js +226 -0
  108. package/dist/core/spawnManager.js +197 -0
  109. package/dist/core/statusVerbs.js +43 -0
  110. package/dist/core/swarmManager.js +109 -0
  111. package/dist/core/taskQueue.js +119 -0
  112. package/dist/core/taskRecovery.js +128 -0
  113. package/dist/core/taskState.js +168 -0
  114. package/dist/core/telegramBot.js +152 -0
  115. package/dist/core/todoManager.js +70 -0
  116. package/dist/core/toolNameRepair.js +71 -0
  117. package/dist/core/toolRegistry.js +2730 -0
  118. package/dist/core/tools/calendarTool.js +98 -0
  119. package/dist/core/tools/companyFilingsTool.js +98 -0
  120. package/dist/core/tools/gmailTool.js +87 -0
  121. package/dist/core/tools/marketDataTool.js +135 -0
  122. package/dist/core/tools/socialResearchTool.js +121 -0
  123. package/dist/core/truthCheck.js +57 -0
  124. package/dist/core/updateChecker.js +74 -0
  125. package/dist/core/userCognitionProfile.js +238 -0
  126. package/dist/core/userProfile.js +341 -0
  127. package/dist/core/version.js +5 -0
  128. package/dist/core/visionAnalyze.js +161 -0
  129. package/dist/core/voice/audio.js +187 -0
  130. package/dist/core/voice/stt.js +226 -0
  131. package/dist/core/voice/tts.js +310 -0
  132. package/dist/core/voiceInput.js +118 -0
  133. package/dist/core/voiceOutput.js +130 -0
  134. package/dist/core/webSearch.js +326 -0
  135. package/dist/core/workflowTracker.js +72 -0
  136. package/dist/core/workspaceMemory.js +54 -0
  137. package/dist/core/youtubeTranscript.js +224 -0
  138. package/dist/integrations/computerUse/apiRegistry.js +113 -0
  139. package/dist/integrations/computerUse/screenAgent.js +203 -0
  140. package/dist/integrations/computerUse/visionLoop.js +296 -0
  141. package/dist/memory/memoryLayers.js +143 -0
  142. package/dist/providers/boa.js +93 -0
  143. package/dist/providers/cerebras.js +70 -0
  144. package/dist/providers/custom.js +89 -0
  145. package/dist/providers/gemini.js +82 -0
  146. package/dist/providers/groq.js +92 -0
  147. package/dist/providers/index.js +149 -0
  148. package/dist/providers/nvidia.js +70 -0
  149. package/dist/providers/ollama.js +99 -0
  150. package/dist/providers/openrouter.js +74 -0
  151. package/dist/providers/router.js +497 -0
  152. package/dist/providers/types.js +6 -0
  153. package/dist/security/browserVault.js +129 -0
  154. package/dist/security/dataGuard.js +89 -0
  155. package/dist/tools/eonetTool.js +72 -0
  156. package/dist/types/computerUse.js +2 -0
  157. package/dist/types/executor.js +2 -0
  158. package/dist-bundle/cli.js +357859 -0
  159. package/package.json +256 -0
@@ -0,0 +1,384 @@
1
+ "use strict";
2
+ // ============================================================
3
+ // DevOS — Autonomous AI Execution System
4
+ // Copyright (c) 2026 Shiva Deore. All rights reserved.
5
+ // ============================================================
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.inferTags = inferTags;
11
+ exports.sanitizeSkillId = sanitizeSkillId;
12
+ exports.validateFrontmatter = validateFrontmatter;
13
+ exports.buildFrontmatter = buildFrontmatter;
14
+ exports.writeSkillDraft = writeSkillDraft;
15
+ exports.approveDraft = approveDraft;
16
+ exports.rejectDraft = rejectDraft;
17
+ exports.setSkillEnabled = setSkillEnabled;
18
+ exports.writeSkillFromTask = writeSkillFromTask;
19
+ exports.listPending = listPending;
20
+ // core/skillWriter.ts — Writes auto-generated skill drafts to disk.
21
+ // Used by A2 (/learn), A3 (passiveSkillObserver), and A4 (skillLibrary install).
22
+ const fs_1 = __importDefault(require("fs"));
23
+ const path_1 = __importDefault(require("path"));
24
+ // ── inferTags ─────────────────────────────────────────────────
25
+ // Derives agentskills.io tags from tool names and content.
26
+ function inferTags(toolsUsed, content = '') {
27
+ const tags = new Set();
28
+ const allText = [...toolsUsed, content].join(' ').toLowerCase();
29
+ if (/browser|navigate|open_browser|web_search|fetch|scrape/.test(allText))
30
+ tags.add('web');
31
+ if (/python|shell_exec|run_python|exec|script/.test(allText))
32
+ tags.add('code');
33
+ if (/read_file|write_file|list_files|file|disk|path|folder/.test(allText))
34
+ tags.add('files');
35
+ if (/stock|nse|market|price|finance|invest|trade|ticker/.test(allText))
36
+ tags.add('finance');
37
+ if (/notify|schedule_reminder|cron|alarm|reminder/.test(allText))
38
+ tags.add('automation');
39
+ if (/email|mail|smtp|imap|send_email/.test(allText))
40
+ tags.add('email');
41
+ if (/slack|discord|whatsapp|telegram|message|send_message/.test(allText))
42
+ tags.add('messaging');
43
+ if (tags.size === 0)
44
+ tags.add('general');
45
+ return Array.from(tags);
46
+ }
47
+ // ── sanitizeSkillId ────────────────────────────────────────────
48
+ // Converts an arbitrary skill name to a safe directory/id slug.
49
+ function sanitizeSkillId(name) {
50
+ return name
51
+ .toLowerCase()
52
+ .replace(/[^a-z0-9]+/g, '-')
53
+ .replace(/^-+|-+$/g, '')
54
+ .slice(0, 64) || 'unnamed-skill';
55
+ }
56
+ // ── validateFrontmatter ────────────────────────────────────────
57
+ // Validates YAML frontmatter (between --- markers).
58
+ function validateFrontmatter(content) {
59
+ const errors = [];
60
+ const match = content.match(/^---\s*([\s\S]*?)\s*---/);
61
+ if (!match) {
62
+ errors.push('Missing frontmatter (--- block)');
63
+ return { valid: false, errors };
64
+ }
65
+ const fm = match[1];
66
+ if (!fm.match(/^name:\s*.+$/m))
67
+ errors.push('Missing required field: name');
68
+ if (!fm.match(/^description:\s*.+$/m))
69
+ errors.push('Missing required field: description');
70
+ return { valid: errors.length === 0, errors };
71
+ }
72
+ // ── buildFrontmatter ───────────────────────────────────────────
73
+ // Renders a frontmatter YAML block from a SkillMeta object.
74
+ function buildFrontmatter(meta) {
75
+ const lines = ['---'];
76
+ lines.push(`name: ${meta.name}`);
77
+ lines.push(`description: ${meta.description}`);
78
+ if (meta.category)
79
+ lines.push(`category: ${meta.category}`);
80
+ if (meta.platform)
81
+ lines.push(`platform: ${meta.platform ?? 'any'}`);
82
+ lines.push(`version: ${meta.version ?? '1.0.0'}`);
83
+ const tags = (meta.tags ?? []).join(', ');
84
+ lines.push(`tags: [${tags}]`);
85
+ if (meta.origin)
86
+ lines.push(`origin: ${meta.origin}`);
87
+ lines.push(`enabled: ${meta.enabled ?? false}`);
88
+ if (meta.source)
89
+ lines.push(`source: ${meta.source}`);
90
+ lines.push('---');
91
+ return lines.join('\n');
92
+ }
93
+ // ── writeSkillDraft ────────────────────────────────────────────
94
+ // Writes a SkillDraft to `skills/learned/pending/<id>/SKILL.md`
95
+ // or `skills/installed/<id>/SKILL.md`.
96
+ // Throws if the directory already exists (no silent overwrite).
97
+ async function writeSkillDraft(draft, targetDir) {
98
+ const cwd = process.cwd();
99
+ const id = sanitizeSkillId(draft.name);
100
+ const baseDir = targetDir === 'installed'
101
+ ? path_1.default.join(cwd, 'skills', 'installed')
102
+ : path_1.default.join(cwd, 'skills', 'learned', 'pending');
103
+ const dir = path_1.default.join(baseDir, id);
104
+ if (fs_1.default.existsSync(dir)) {
105
+ throw new Error(`Skill "${id}" already exists at ${dir}. Use a different name or delete the existing draft.`);
106
+ }
107
+ fs_1.default.mkdirSync(dir, { recursive: true });
108
+ const frontmatter = buildFrontmatter({
109
+ name: draft.name,
110
+ description: draft.description,
111
+ category: draft.category,
112
+ platform: draft.platform ?? 'any',
113
+ version: draft.version ?? '1.0.0',
114
+ tags: draft.tags ?? [],
115
+ origin: draft.source === 'library_install' ? 'community' : 'local',
116
+ enabled: false,
117
+ source: draft.source,
118
+ });
119
+ const timestamp = new Date().toISOString();
120
+ const header = `<!-- auto-generated: ${timestamp} -->\n`;
121
+ const body = draft.content.trim();
122
+ const fileContent = `${frontmatter}\n\n${header}${body}\n`;
123
+ const filePath = path_1.default.join(dir, 'SKILL.md');
124
+ fs_1.default.writeFileSync(filePath, fileContent, 'utf-8');
125
+ // Write metadata sidecar (for review UI)
126
+ const meta = {
127
+ id,
128
+ name: draft.name,
129
+ description: draft.description,
130
+ source: draft.source,
131
+ sourceDetails: draft.sourceDetails ?? {},
132
+ createdAt: timestamp,
133
+ enabled: false,
134
+ };
135
+ fs_1.default.writeFileSync(path_1.default.join(dir, 'meta.json'), JSON.stringify(meta, null, 2) + '\n', 'utf-8');
136
+ // Write skill.json (agentskills.io compatibility manifest)
137
+ const toolCalls = draft.sourceDetails?.toolCalls ?? [];
138
+ const toolNames = Array.isArray(toolCalls) ? toolCalls.map((t) => t.tool ?? t).filter(Boolean) : [];
139
+ const skillJson = {
140
+ name: id,
141
+ version: draft.version ?? '1.0.0',
142
+ description: draft.description,
143
+ author: 'local',
144
+ license: 'MIT',
145
+ tools: toolNames,
146
+ trigger_phrases: [],
147
+ compatible_agents: ['aiden'],
148
+ min_agent_version: '3.0.0',
149
+ tags: draft.tags?.length ? draft.tags : inferTags(toolNames, draft.content),
150
+ created: timestamp,
151
+ };
152
+ fs_1.default.writeFileSync(path_1.default.join(dir, 'skill.json'), JSON.stringify(skillJson, null, 2) + '\n', 'utf-8');
153
+ return { id, filePath, dir };
154
+ }
155
+ // ── approveDraft ──────────────────────────────────────────────
156
+ // Moves a pending skill to skills/learned/approved/ and sets enabled:true.
157
+ function approveDraft(id) {
158
+ const cwd = process.cwd();
159
+ const pendDir = path_1.default.join(cwd, 'skills', 'learned', 'pending', id);
160
+ const approDir = path_1.default.join(cwd, 'skills', 'learned', 'approved', id);
161
+ if (!fs_1.default.existsSync(pendDir))
162
+ throw new Error(`Pending skill "${id}" not found`);
163
+ if (fs_1.default.existsSync(approDir))
164
+ throw new Error(`Approved skill "${id}" already exists`);
165
+ // Enable in SKILL.md before moving
166
+ const skillFile = path_1.default.join(pendDir, 'SKILL.md');
167
+ if (fs_1.default.existsSync(skillFile)) {
168
+ let content = fs_1.default.readFileSync(skillFile, 'utf-8');
169
+ content = content.replace(/^enabled:\s*false/m, 'enabled: true');
170
+ fs_1.default.writeFileSync(skillFile, content, 'utf-8');
171
+ }
172
+ fs_1.default.mkdirSync(path_1.default.join(cwd, 'skills', 'learned', 'approved'), { recursive: true });
173
+ fs_1.default.renameSync(pendDir, approDir);
174
+ return approDir;
175
+ }
176
+ // ── rejectDraft ───────────────────────────────────────────────
177
+ // Deletes a pending skill and records it in .rejected.json.
178
+ function rejectDraft(id) {
179
+ const cwd = process.cwd();
180
+ const pendDir = path_1.default.join(cwd, 'skills', 'learned', 'pending', id);
181
+ if (!fs_1.default.existsSync(pendDir))
182
+ throw new Error(`Pending skill "${id}" not found`);
183
+ // Read meta for logging
184
+ let meta = { id };
185
+ try {
186
+ meta = JSON.parse(fs_1.default.readFileSync(path_1.default.join(pendDir, 'meta.json'), 'utf-8'));
187
+ }
188
+ catch { }
189
+ // Remove directory
190
+ fs_1.default.rmSync(pendDir, { recursive: true, force: true });
191
+ // Append to .rejected.json
192
+ const rejLog = path_1.default.join(cwd, 'skills', 'learned', '.rejected.json');
193
+ let log = [];
194
+ try {
195
+ log = JSON.parse(fs_1.default.readFileSync(rejLog, 'utf-8'));
196
+ }
197
+ catch { }
198
+ log.push({ ...meta, rejectedAt: new Date().toISOString() });
199
+ fs_1.default.writeFileSync(rejLog, JSON.stringify(log, null, 2) + '\n', 'utf-8');
200
+ }
201
+ // ── setSkillEnabled ───────────────────────────────────────────
202
+ // Flips the enabled: flag in a skill's SKILL.md and returns the new state.
203
+ function setSkillEnabled(filePath, enabled) {
204
+ if (!fs_1.default.existsSync(filePath))
205
+ throw new Error(`Skill file not found: ${filePath}`);
206
+ let content = fs_1.default.readFileSync(filePath, 'utf-8');
207
+ if (/^enabled:/m.test(content)) {
208
+ content = content.replace(/^enabled:\s*(true|false)/m, `enabled: ${enabled}`);
209
+ }
210
+ else {
211
+ // Insert after version line or before closing ---
212
+ content = content.replace(/^(version:.+)$/m, `$1\nenabled: ${enabled}`);
213
+ }
214
+ fs_1.default.writeFileSync(filePath, content, 'utf-8');
215
+ }
216
+ // Simple Dice-coefficient token similarity (BM25-lite, good enough for dedup)
217
+ function tokenSimilarity(a, b) {
218
+ const tok = (s) => new Set(s.toLowerCase().replace(/[^a-z0-9 ]/g, ' ').split(/\s+/).filter(Boolean));
219
+ const sa = tok(a);
220
+ const sb = tok(b);
221
+ let intersect = 0;
222
+ sa.forEach(t => { if (sb.has(t))
223
+ intersect++; });
224
+ return (2 * intersect) / (sa.size + sb.size + 0.001);
225
+ }
226
+ const STOP_WORDS = new Set([
227
+ 'a', 'an', 'the', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
228
+ 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'could',
229
+ 'should', 'may', 'might', 'can', 'to', 'for', 'of', 'in', 'on', 'at',
230
+ 'by', 'with', 'and', 'or', 'but', 'not', 'this', 'that', 'it', 'i',
231
+ 'you', 'me', 'my', 'your', 'we', 'our', 'they', 'their', 'what',
232
+ 'how', 'where', 'when', 'why', 'which', 'please', 'just', 'get',
233
+ 'make', 'let', 'go', 'run', 'show', 'tell', 'find', 'open',
234
+ ]);
235
+ function skillNameFromMessage(msg) {
236
+ const words = msg
237
+ .toLowerCase()
238
+ .replace(/[^a-z0-9 ]/g, ' ')
239
+ .split(/\s+/)
240
+ .filter(w => w.length > 2 && !STOP_WORDS.has(w))
241
+ .slice(0, 5);
242
+ return (words.join('_') || 'task').slice(0, 48);
243
+ }
244
+ function toTitleCase(s) {
245
+ return s.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
246
+ }
247
+ async function writeSkillFromTask(args) {
248
+ const { userMessage, aiReply, toolsUsed, success } = args;
249
+ // Gate: skip trivial or failed exchanges
250
+ if (!success || toolsUsed.length < 2)
251
+ return null;
252
+ try {
253
+ const cwd = process.cwd();
254
+ const learnedDir = path_1.default.join(cwd, 'workspace', 'skills', 'learned');
255
+ fs_1.default.mkdirSync(learnedDir, { recursive: true });
256
+ const skillName = skillNameFromMessage(userMessage);
257
+ // Dedup: skip if a very similar skill already exists (Dice > 0.80)
258
+ if (fs_1.default.existsSync(learnedDir)) {
259
+ for (const entry of fs_1.default.readdirSync(learnedDir, { withFileTypes: true })) {
260
+ if (!entry.isDirectory())
261
+ continue;
262
+ const existingName = entry.name.replace(/_/g, ' ');
263
+ if (tokenSimilarity(skillName.replace(/_/g, ' '), existingName) > 0.80) {
264
+ // Skill already exists — bump success count instead
265
+ const metaPath = path_1.default.join(learnedDir, entry.name, 'meta.json');
266
+ if (fs_1.default.existsSync(metaPath)) {
267
+ try {
268
+ const meta = JSON.parse(fs_1.default.readFileSync(metaPath, 'utf-8'));
269
+ meta.successCount = (meta.successCount || 1) + 1;
270
+ meta.lastUsed = Date.now();
271
+ meta.confidence = Math.min(0.99, (meta.successCount) / (meta.successCount + (meta.failCount || 0) + 1));
272
+ fs_1.default.writeFileSync(metaPath, JSON.stringify(meta, null, 2) + '\n', 'utf-8');
273
+ }
274
+ catch { }
275
+ }
276
+ return null;
277
+ }
278
+ }
279
+ }
280
+ const skillDir = path_1.default.join(learnedDir, skillName);
281
+ // If exact dir exists, just bump meta
282
+ if (fs_1.default.existsSync(skillDir)) {
283
+ const metaPath = path_1.default.join(skillDir, 'meta.json');
284
+ if (fs_1.default.existsSync(metaPath)) {
285
+ try {
286
+ const meta = JSON.parse(fs_1.default.readFileSync(metaPath, 'utf-8'));
287
+ meta.successCount = (meta.successCount || 1) + 1;
288
+ meta.lastUsed = Date.now();
289
+ meta.confidence = Math.min(0.99, (meta.successCount) / (meta.successCount + (meta.failCount || 0) + 1));
290
+ fs_1.default.writeFileSync(metaPath, JSON.stringify(meta, null, 2) + '\n', 'utf-8');
291
+ }
292
+ catch { }
293
+ }
294
+ return null;
295
+ }
296
+ fs_1.default.mkdirSync(skillDir, { recursive: true });
297
+ const title = toTitleCase(skillName);
298
+ const descSnippet = userMessage.slice(0, 100).replace(/\n/g, ' ');
299
+ const toolList = toolsUsed.join(', ');
300
+ const exampleQ = userMessage.slice(0, 200).replace(/\n/g, ' ');
301
+ const exampleA = aiReply.slice(0, 200).replace(/\n/g, ' ');
302
+ // Build numbered steps from tool sequence
303
+ const stepsBlock = toolsUsed
304
+ .map((t, i) => `${i + 1}. [${t}] — execute ${t} step`)
305
+ .join('\n');
306
+ const skillMd = [
307
+ '---',
308
+ `name: ${skillName}`,
309
+ `description: ${descSnippet}`,
310
+ `version: 1.0.0`,
311
+ `origin: local`,
312
+ `confidence: medium`,
313
+ `trigger_phrase: "${userMessage.slice(0, 80).replace(/"/g, "'")}"`,
314
+ `tools_used: [${toolList}]`,
315
+ '---',
316
+ '',
317
+ `# ${title}`,
318
+ '',
319
+ '## When to use this skill',
320
+ `Use this when the user asks to ${descSnippet.toLowerCase().slice(0, 80)}.`,
321
+ '',
322
+ '## Steps',
323
+ stepsBlock,
324
+ '',
325
+ '## Example',
326
+ `User: "${exampleQ}"`,
327
+ `Result: "${exampleA}"`,
328
+ '',
329
+ ].join('\n');
330
+ const metaJson = {
331
+ name: skillName,
332
+ taskPattern: userMessage.slice(0, 200),
333
+ toolSequence: toolsUsed,
334
+ successCount: 1,
335
+ failCount: 0,
336
+ confidence: 0.5,
337
+ promoted: false,
338
+ createdAt: Date.now(),
339
+ lastUsed: Date.now(),
340
+ avgDuration: 0,
341
+ };
342
+ const taskSkillJson = {
343
+ name: skillName,
344
+ version: '1.0.0',
345
+ description: descSnippet,
346
+ author: 'local',
347
+ license: 'MIT',
348
+ tools: toolsUsed,
349
+ trigger_phrases: [userMessage.slice(0, 80).replace(/"/g, "'")],
350
+ compatible_agents: ['aiden'],
351
+ min_agent_version: '3.0.0',
352
+ tags: inferTags(toolsUsed, userMessage),
353
+ created: new Date().toISOString(),
354
+ };
355
+ fs_1.default.writeFileSync(path_1.default.join(skillDir, 'SKILL.md'), skillMd, 'utf-8');
356
+ fs_1.default.writeFileSync(path_1.default.join(skillDir, 'meta.json'), JSON.stringify(metaJson, null, 2) + '\n', 'utf-8');
357
+ fs_1.default.writeFileSync(path_1.default.join(skillDir, 'skill.json'), JSON.stringify(taskSkillJson, null, 2) + '\n', 'utf-8');
358
+ console.log(`[SkillWriter] Wrote skill "${skillName}" → ${skillDir}`);
359
+ return { skillName, path: skillDir };
360
+ }
361
+ catch (err) {
362
+ console.warn('[SkillWriter] writeSkillFromTask failed (non-fatal):', err?.message);
363
+ return null;
364
+ }
365
+ }
366
+ // ── listPending ───────────────────────────────────────────────
367
+ // Returns all pending skill IDs with their metadata.
368
+ function listPending() {
369
+ const cwd = process.cwd();
370
+ const pendDir = path_1.default.join(cwd, 'skills', 'learned', 'pending');
371
+ if (!fs_1.default.existsSync(pendDir))
372
+ return [];
373
+ return fs_1.default.readdirSync(pendDir, { withFileTypes: true })
374
+ .filter(e => e.isDirectory())
375
+ .map(e => {
376
+ try {
377
+ const meta = JSON.parse(fs_1.default.readFileSync(path_1.default.join(pendDir, e.name, 'meta.json'), 'utf-8'));
378
+ return { id: e.name, name: meta.name || e.name, description: meta.description || '', source: meta.source || '', createdAt: meta.createdAt || '' };
379
+ }
380
+ catch {
381
+ return { id: e.name, name: e.name, description: '', source: 'unknown', createdAt: '' };
382
+ }
383
+ });
384
+ }
@@ -0,0 +1,226 @@
1
+ "use strict";
2
+ // ============================================================
3
+ // DevOS — Autonomous AI Execution System
4
+ // Copyright (c) 2026 Shiva Deore. All rights reserved.
5
+ // ============================================================
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ var __importDefault = (this && this.__importDefault) || function (mod) {
40
+ return (mod && mod.__esModule) ? mod : { "default": mod };
41
+ };
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.SLASH_MIRROR_TOOL_NAMES = void 0;
44
+ exports.registerSlashMirrorTools = registerSlashMirrorTools;
45
+ // core/slashAsTool.ts — Phase 3: Slash commands mirrored as agent tools.
46
+ //
47
+ // Exposes read-only informational slash commands as callable tools so the
48
+ // planner can query system state without the user typing them manually.
49
+ // State-mutating commands (/new, /reset, /model, etc.) are NOT exposed.
50
+ //
51
+ // Call registerSlashMirrorTools() once at server startup.
52
+ const fs_1 = __importDefault(require("fs"));
53
+ const path_1 = __importDefault(require("path"));
54
+ const os_1 = __importDefault(require("os"));
55
+ const toolRegistry_1 = require("./toolRegistry");
56
+ const conversationMemory_1 = require("./conversationMemory");
57
+ const learningMemory_1 = require("./learningMemory");
58
+ const skillLoader_1 = require("./skillLoader");
59
+ const costTracker_1 = require("./costTracker");
60
+ const goalTracker_1 = require("./goalTracker");
61
+ const index_1 = require("../providers/index");
62
+ // ── Helpers ───────────────────────────────────────────────────────────────────
63
+ /** Strip ANSI escape codes so the LLM gets plain text. */
64
+ function stripAnsi(s) {
65
+ // eslint-disable-next-line no-control-regex
66
+ return s.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '');
67
+ }
68
+ const LESSONS_PATH = path_1.default.join(process.cwd(), 'workspace', 'LESSONS.md');
69
+ function loadLessonsText() {
70
+ try {
71
+ if (fs_1.default.existsSync(LESSONS_PATH))
72
+ return fs_1.default.readFileSync(LESSONS_PATH, 'utf-8').trim();
73
+ }
74
+ catch { }
75
+ return '';
76
+ }
77
+ // ── Mirror tool implementations ───────────────────────────────────────────────
78
+ async function toolStatus(_) {
79
+ const uptimeSec = Math.floor(process.uptime());
80
+ const ramMB = Math.round(process.memoryUsage().heapUsed / 1024 / 1024);
81
+ const sessions = conversationMemory_1.conversationMemory.getSessions().length;
82
+ const lines = [
83
+ 'SYSTEM STATUS',
84
+ `Uptime ${Math.floor(uptimeSec / 60)}m ${uptimeSec % 60}s`,
85
+ `RAM ${ramMB} MB`,
86
+ `Sessions ${sessions}`,
87
+ `Platform ${os_1.default.platform()} ${os_1.default.arch()}`,
88
+ `Node ${process.version}`,
89
+ ];
90
+ return { success: true, output: lines.join('\n') };
91
+ }
92
+ async function toolAnalytics(_) {
93
+ const stats = learningMemory_1.learningMemory.getStats();
94
+ const lines = [
95
+ 'LEARNING ANALYTICS',
96
+ `Total tasks ${stats.total}`,
97
+ `Success rate ${stats.successRate}%`,
98
+ `Avg duration ${stats.avgDuration}ms`,
99
+ ];
100
+ return { success: true, output: lines.join('\n') };
101
+ }
102
+ async function toolSpend(_) {
103
+ try {
104
+ const summary = costTracker_1.costTracker.getDailySummary();
105
+ const byProvider = Object.entries(summary.byProvider || {})
106
+ .map(([p, c]) => ` ${p}: $${c.toFixed(4)}`)
107
+ .join('\n');
108
+ const lines = [
109
+ `SPEND — ${summary.date}`,
110
+ `Total $${summary.totalUSD.toFixed(4)}`,
111
+ `User $${summary.userUSD.toFixed(4)}`,
112
+ `System $${summary.systemUSD.toFixed(4)}`,
113
+ byProvider ? `By provider:\n${byProvider}` : '',
114
+ ].filter(Boolean);
115
+ return { success: true, output: lines.join('\n') };
116
+ }
117
+ catch {
118
+ return { success: true, output: 'Spend data unavailable.' };
119
+ }
120
+ }
121
+ async function toolMemoryShow(_) {
122
+ const facts = conversationMemory_1.conversationMemory.getFacts();
123
+ const history = conversationMemory_1.conversationMemory.getRecentHistory();
124
+ const lines = [
125
+ 'MEMORY FACTS',
126
+ facts.lastFilesCreated.length ? `Files created : ${facts.lastFilesCreated.join(', ')}` : '',
127
+ facts.lastSearchQueries.length ? `Last searches : ${facts.lastSearchQueries.join(', ')}` : '',
128
+ facts.lastToolsUsed.length ? `Last tools : ${facts.lastToolsUsed.join(', ')}` : '',
129
+ facts.mentionedEntities.length ? `Topics : ${facts.mentionedEntities.slice(-10).join(', ')}` : '',
130
+ '',
131
+ `Recent exchanges: ${history.length}`,
132
+ ...history.slice(-3).map(e => e.userMessage ? ` User: ${e.userMessage.slice(0, 80)}` : '').filter(Boolean),
133
+ ].filter(l => l !== undefined);
134
+ return { success: true, output: lines.join('\n') };
135
+ }
136
+ async function toolLessons(_) {
137
+ const lessons = loadLessonsText();
138
+ if (!lessons)
139
+ return { success: true, output: 'No lessons recorded yet.' };
140
+ return { success: true, output: `LESSONS (permanent failure rules):\n${lessons}` };
141
+ }
142
+ async function toolSkillsList(_) {
143
+ const skills = skillLoader_1.skillLoader.loadAll();
144
+ if (skills.length === 0)
145
+ return { success: true, output: 'No skills loaded.' };
146
+ const lines = [
147
+ `SKILLS (${skills.length} loaded)`,
148
+ ...skills.map(s => ` ${s.name.padEnd(20)} ${s.description || ''}`),
149
+ ];
150
+ return { success: true, output: lines.join('\n') };
151
+ }
152
+ async function toolToolsList(_) {
153
+ // Import lazily to avoid circular dependency
154
+ const { TOOLS } = await Promise.resolve().then(() => __importStar(require('./toolRegistry')));
155
+ const names = Object.keys(TOOLS).sort();
156
+ return { success: true, output: `TOOLS (${names.length}):\n${names.join(', ')}` };
157
+ }
158
+ async function toolWhoami(_) {
159
+ const cfg = (0, index_1.loadConfig)();
160
+ const userName = cfg.userName || process.env.USERNAME || os_1.default.userInfo().username || 'User';
161
+ const homeDir = os_1.default.homedir();
162
+ const lines = [
163
+ 'USER PROFILE',
164
+ `Name ${userName}`,
165
+ `Home ${homeDir}`,
166
+ `Platform ${os_1.default.platform()}`,
167
+ ];
168
+ return { success: true, output: lines.join('\n') };
169
+ }
170
+ async function toolChannelsStatus(_) {
171
+ try {
172
+ const cfg = (0, index_1.loadConfig)();
173
+ const apis = cfg?.providers?.apis || [];
174
+ const lines = [
175
+ 'PROVIDER CHANNELS',
176
+ ...apis.map((api) => {
177
+ const key = String(api.key || '');
178
+ const hasKey = key.startsWith('env:')
179
+ ? !!(process.env[key.replace('env:', '')] || '').trim()
180
+ : key.trim().length > 0;
181
+ const status = !api.enabled ? 'disabled' : api.rateLimited ? 'rate-limited' : hasKey ? 'active' : 'no key';
182
+ return ` ${(api.name || api.provider || '').padEnd(20)} ${api.model || ''} [${status}]`;
183
+ }),
184
+ ];
185
+ return { success: true, output: lines.join('\n') };
186
+ }
187
+ catch {
188
+ return { success: true, output: 'Provider status unavailable.' };
189
+ }
190
+ }
191
+ // ── Goals tool ────────────────────────────────────────────────────────────────
192
+ async function toolGoals(_) {
193
+ const summary = (0, goalTracker_1.getActiveGoalsSummary)();
194
+ return { success: true, output: summary ? `ACTIVE GOALS:\n${summary}` : 'No active goals.' };
195
+ }
196
+ // ── Registration ──────────────────────────────────────────────────────────────
197
+ const MIRROR_TOOLS = [
198
+ { name: 'status', description: 'Show system status: uptime, RAM, session count', fn: toolStatus },
199
+ { name: 'analytics', description: 'Show learning analytics: task count, success rate', fn: toolAnalytics },
200
+ { name: 'spend', description: 'Show today\'s token cost and spend by provider', fn: toolSpend },
201
+ { name: 'memory_show', description: 'Show conversation memory facts and recent history', fn: toolMemoryShow },
202
+ { name: 'lessons', description: 'Show permanent failure rules learned from past tasks', fn: toolLessons },
203
+ { name: 'skills_list', description: 'List all loaded skills with descriptions', fn: toolSkillsList },
204
+ { name: 'tools_list', description: 'List all registered tool names', fn: toolToolsList },
205
+ { name: 'whoami', description: 'Show current user profile: name, home dir, platform', fn: toolWhoami },
206
+ { name: 'channels_status', description: 'Show provider channel status: active, disabled, no-key', fn: toolChannelsStatus },
207
+ { name: 'goals', description: 'Show currently active goals', fn: toolGoals },
208
+ ];
209
+ /** Names of all slash mirror tools — used to add them to VALID_TOOLS / ALLOWED_TOOLS. */
210
+ exports.SLASH_MIRROR_TOOL_NAMES = MIRROR_TOOLS.map(t => t.name);
211
+ /**
212
+ * Register all read-only slash mirror tools into the tool registry.
213
+ * Call once at server startup.
214
+ */
215
+ function registerSlashMirrorTools() {
216
+ const isDebug = (process.env.AIDEN_LOG_LEVEL || 'info') === 'debug';
217
+ for (const { name, description, fn } of MIRROR_TOOLS) {
218
+ (0, toolRegistry_1.registerExternalTool)(name, fn, 'slash-mirror');
219
+ if (isDebug) {
220
+ console.log('[SlashAsTool] Registered mirror tool: ' + name + ' — ' + description);
221
+ }
222
+ }
223
+ if (!isDebug) {
224
+ console.log('[SlashAsTool] Registered ' + MIRROR_TOOLS.length + ' mirror tools (AIDEN_LOG_LEVEL=debug for detail)');
225
+ }
226
+ }