@causyne/agent 0.0.0-stage → 1.10.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 (274) hide show
  1. package/LICENSE +102 -0
  2. package/README.md +31 -2
  3. package/SECURITY.md +24 -0
  4. package/bin/causyne.js +13 -0
  5. package/docs/ARCHITECTURE.md +63 -0
  6. package/docs/PROVENANCE.md +29 -0
  7. package/docs/SECURITY_REVIEW.md +89 -0
  8. package/docs/THIRD_PARTY_NOTICES.md +49 -0
  9. package/native-skills/ai-engineering/context-window-management/SKILL.md +43 -0
  10. package/native-skills/ai-engineering/llm-evaluation/SKILL.md +46 -0
  11. package/native-skills/ai-engineering/model-cost-and-latency/SKILL.md +46 -0
  12. package/native-skills/ai-engineering/prompt-construction/SKILL.md +42 -0
  13. package/native-skills/ai-engineering/retrieval-augmented-generation/SKILL.md +42 -0
  14. package/native-skills/ai-engineering/structured-output-and-schemas/SKILL.md +45 -0
  15. package/native-skills/ai-engineering/tool-calling-agents/SKILL.md +43 -0
  16. package/native-skills/android/app-performance-profiling/SKILL.md +42 -0
  17. package/native-skills/android/background-work-scheduling/SKILL.md +47 -0
  18. package/native-skills/android/compose-state-and-recomposition/SKILL.md +43 -0
  19. package/native-skills/android/gradle-build-configuration/SKILL.md +41 -0
  20. package/native-skills/android/lifecycle-and-leaks/SKILL.md +46 -0
  21. package/native-skills/android/play-store-release/SKILL.md +43 -0
  22. package/native-skills/android/room-and-persistence/SKILL.md +40 -0
  23. package/native-skills/backend/authentication-and-sessions/SKILL.md +45 -0
  24. package/native-skills/backend/background-jobs-and-queues/SKILL.md +42 -0
  25. package/native-skills/backend/caching-strategy/SKILL.md +44 -0
  26. package/native-skills/backend/graceful-shutdown/SKILL.md +42 -0
  27. package/native-skills/backend/rate-limiting-and-quotas/SKILL.md +40 -0
  28. package/native-skills/backend/rest-api-design/SKILL.md +40 -0
  29. package/native-skills/backend/webhook-delivery-and-receipt/SKILL.md +43 -0
  30. package/native-skills/cloud/cost-optimisation/SKILL.md +46 -0
  31. package/native-skills/cloud/iam-least-privilege/SKILL.md +43 -0
  32. package/native-skills/cloud/infrastructure-as-code/SKILL.md +43 -0
  33. package/native-skills/cloud/multi-region-and-failover/SKILL.md +43 -0
  34. package/native-skills/cloud/serverless-patterns/SKILL.md +47 -0
  35. package/native-skills/data/data-quality-monitoring/SKILL.md +51 -0
  36. package/native-skills/data/etl-pipeline-reliability/SKILL.md +43 -0
  37. package/native-skills/data/exploratory-analysis/SKILL.md +43 -0
  38. package/native-skills/data/metric-definition/SKILL.md +42 -0
  39. package/native-skills/data/notebook-to-production/SKILL.md +43 -0
  40. package/native-skills/database/backup-and-recovery/SKILL.md +43 -0
  41. package/native-skills/database/connection-pooling/SKILL.md +42 -0
  42. package/native-skills/database/data-integrity-and-constraints/SKILL.md +42 -0
  43. package/native-skills/database/query-optimisation/SKILL.md +38 -0
  44. package/native-skills/database/safe-migrations/SKILL.md +47 -0
  45. package/native-skills/database/schema-design/SKILL.md +38 -0
  46. package/native-skills/database/transactions-and-isolation/SKILL.md +41 -0
  47. package/native-skills/design/colour-system-construction/SKILL.md +38 -0
  48. package/native-skills/design/design-direction-brief/SKILL.md +41 -0
  49. package/native-skills/design/motion-and-transitions/SKILL.md +38 -0
  50. package/native-skills/design/responsive-strategy/SKILL.md +39 -0
  51. package/native-skills/design/spacing-and-rhythm/SKILL.md +38 -0
  52. package/native-skills/design/type-scale-and-hierarchy/SKILL.md +39 -0
  53. package/native-skills/design/visual-qa-loop/SKILL.md +42 -0
  54. package/native-skills/devops/docker-multi-stage-builds/SKILL.md +60 -0
  55. package/native-skills/devops/github-actions-ci/SKILL.md +60 -0
  56. package/native-skills/devops/incident-triage/SKILL.md +38 -0
  57. package/native-skills/devops/kubernetes-deployment-hardening/SKILL.md +64 -0
  58. package/native-skills/devops/observability-baseline/SKILL.md +38 -0
  59. package/native-skills/devops/secret-management/SKILL.md +40 -0
  60. package/native-skills/devops/terraform-state-and-modules/SKILL.md +36 -0
  61. package/native-skills/devops/zero-downtime-deploys/SKILL.md +40 -0
  62. package/native-skills/git/bisect-regression-hunt/SKILL.md +43 -0
  63. package/native-skills/git/branch-strategy/SKILL.md +39 -0
  64. package/native-skills/git/commit-hygiene/SKILL.md +41 -0
  65. package/native-skills/git/history-recovery/SKILL.md +44 -0
  66. package/native-skills/git/large-repository-surgery/SKILL.md +46 -0
  67. package/native-skills/git/merge-conflict-resolution/SKILL.md +42 -0
  68. package/native-skills/media/cinematic-3d-shot/SKILL.md +104 -0
  69. package/native-skills/mobile/app-startup-optimisation/SKILL.md +41 -0
  70. package/native-skills/mobile/cross-platform-tradeoffs/SKILL.md +42 -0
  71. package/native-skills/mobile/deep-linking/SKILL.md +39 -0
  72. package/native-skills/mobile/mobile-storage-security/SKILL.md +45 -0
  73. package/native-skills/mobile/offline-first-sync/SKILL.md +42 -0
  74. package/native-skills/mobile/push-notifications/SKILL.md +38 -0
  75. package/native-skills/performance/algorithmic-complexity/SKILL.md +43 -0
  76. package/native-skills/performance/concurrency-and-parallelism/SKILL.md +42 -0
  77. package/native-skills/performance/load-testing/SKILL.md +42 -0
  78. package/native-skills/performance/memory-and-leak-hunting/SKILL.md +41 -0
  79. package/native-skills/performance/network-and-payload-efficiency/SKILL.md +42 -0
  80. package/native-skills/performance/profiling-methodology/SKILL.md +46 -0
  81. package/native-skills/python/async-correctness/SKILL.md +40 -0
  82. package/native-skills/python/cli-tool-construction/SKILL.md +44 -0
  83. package/native-skills/python/data-processing-pipelines/SKILL.md +38 -0
  84. package/native-skills/python/environment-isolation/SKILL.md +41 -0
  85. package/native-skills/python/packaging-and-distribution/SKILL.md +56 -0
  86. package/native-skills/python/pytest-suite-design/SKILL.md +39 -0
  87. package/native-skills/python/type-hints-and-static-checking/SKILL.md +42 -0
  88. package/native-skills/security/authorization-model/SKILL.md +42 -0
  89. package/native-skills/security/crypto-usage/SKILL.md +48 -0
  90. package/native-skills/security/dependency-supply-chain/SKILL.md +42 -0
  91. package/native-skills/security/input-validation-and-injection/SKILL.md +44 -0
  92. package/native-skills/security/secure-file-uploads/SKILL.md +46 -0
  93. package/native-skills/security/security-headers-and-csp/SKILL.md +44 -0
  94. package/native-skills/security/threat-modelling/SKILL.md +46 -0
  95. package/native-skills/testing/end-to-end-test-stability/SKILL.md +42 -0
  96. package/native-skills/testing/property-based-testing/SKILL.md +46 -0
  97. package/native-skills/testing/regression-test-from-a-bug/SKILL.md +41 -0
  98. package/native-skills/testing/snapshot-and-visual-regression/SKILL.md +42 -0
  99. package/native-skills/testing/test-doubles-and-mocking/SKILL.md +43 -0
  100. package/native-skills/testing/test-strategy-and-pyramid/SKILL.md +39 -0
  101. package/native-skills/testing/writing-good-assertions/SKILL.md +42 -0
  102. package/native-skills/web/accessible-components/SKILL.md +45 -0
  103. package/native-skills/web/api-client-resilience/SKILL.md +39 -0
  104. package/native-skills/web/bundle-size-reduction/SKILL.md +38 -0
  105. package/native-skills/web/core-web-vitals/SKILL.md +40 -0
  106. package/native-skills/web/css-layout-systems/SKILL.md +41 -0
  107. package/native-skills/web/form-validation-ux/SKILL.md +39 -0
  108. package/native-skills/web/react-state-architecture/SKILL.md +41 -0
  109. package/native-skills/web/ssr-hydration-correctness/SKILL.md +45 -0
  110. package/package.json +68 -4
  111. package/src/agentLoop.js +2458 -0
  112. package/src/appChannel.js +109 -0
  113. package/src/approvalGrants.js +66 -0
  114. package/src/auditLog.js +52 -0
  115. package/src/autoUpdate.js +12 -0
  116. package/src/capabilities.js +36 -0
  117. package/src/checkpoints.js +1199 -0
  118. package/src/cliMode.js +638 -0
  119. package/src/commands.js +805 -0
  120. package/src/compiledSkills.js +540 -0
  121. package/src/config.js +130 -0
  122. package/src/contextManager.js +498 -0
  123. package/src/cortex/autoCondenser.js +192 -0
  124. package/src/cortex/provisioner.js +27 -0
  125. package/src/cortex/vectorDb.js +447 -0
  126. package/src/designPalettes.js +99 -0
  127. package/src/devMode.js +6 -0
  128. package/src/embodimentSession.js +180 -0
  129. package/src/entrypoint.js +194 -0
  130. package/src/execSafe.js +21 -0
  131. package/src/gitSnapshot.js +378 -0
  132. package/src/mcp/jsonRpc.js +165 -0
  133. package/src/mcp/mcpClient.js +136 -0
  134. package/src/mcp/mcpRegistry.js +207 -0
  135. package/src/memory.js +62 -0
  136. package/src/memoryManager.js +124 -0
  137. package/src/modelCatalogue.js +132 -0
  138. package/src/modelIds.js +42 -0
  139. package/src/modelRouter.js +145 -0
  140. package/src/outputStore.js +246 -0
  141. package/src/perception.js +124 -0
  142. package/src/planCache.js +437 -0
  143. package/src/procSignal.js +32 -0
  144. package/src/providers/anthropic.js +408 -0
  145. package/src/providers/base.js +328 -0
  146. package/src/providers/dashscope-byok.js +86 -0
  147. package/src/providers/deepseek.js +80 -0
  148. package/src/providers/factory.js +37 -0
  149. package/src/providers/gemini.js +346 -0
  150. package/src/providers/moonshot.js +73 -0
  151. package/src/providers/muse.js +169 -0
  152. package/src/providers/ollama.js +104 -0
  153. package/src/providers/openai-compatible.js +84 -0
  154. package/src/providers/openai.js +20 -0
  155. package/src/providers/qwen-byok.js +76 -0
  156. package/src/providers/xai.js +73 -0
  157. package/src/provisioning/capabilityConsent.js +24 -0
  158. package/src/provisioning/capabilityProvisioner.js +271 -0
  159. package/src/provisioning/capabilityTools.js +29 -0
  160. package/src/reporting.js +373 -0
  161. package/src/sandbox.js +529 -0
  162. package/src/sessionStore.js +279 -0
  163. package/src/skillsManager.js +288 -0
  164. package/src/slopDetector.js +307 -0
  165. package/src/taskBuffer.js +45 -0
  166. package/src/taskShape.js +241 -0
  167. package/src/textDiff.js +150 -0
  168. package/src/tokenTracker.js +560 -0
  169. package/src/tool-scripts/ax_snapshot.applescript +39 -0
  170. package/src/tool-scripts/ax_snapshot.ps1 +10 -0
  171. package/src/tool-scripts/desktop_act.applescript +58 -0
  172. package/src/tool-scripts/resolve_automator.py +119 -0
  173. package/src/toolPacks.js +524 -0
  174. package/src/tools/archive.js +63 -0
  175. package/src/tools/astryxOracle.js +78 -0
  176. package/src/tools/axSnapshot.js +165 -0
  177. package/src/tools/blenderAutomator.js +349 -0
  178. package/src/tools/browserAutomator.js +252 -0
  179. package/src/tools/checkSystemSpecs.js +64 -0
  180. package/src/tools/clipboard.js +36 -0
  181. package/src/tools/codeSearchAst.js +101 -0
  182. package/src/tools/codeSearcher.js +230 -0
  183. package/src/tools/codeTools.js +262 -0
  184. package/src/tools/codebaseSearch.js +75 -0
  185. package/src/tools/createSkill.js +129 -0
  186. package/src/tools/deferredMcpSearch.js +246 -0
  187. package/src/tools/desktopAct.js +208 -0
  188. package/src/tools/desktopOpen.js +34 -0
  189. package/src/tools/dynamicLoader.js +44 -0
  190. package/src/tools/executeProceduralMedia.js +93 -0
  191. package/src/tools/fsDelete.js +51 -0
  192. package/src/tools/fsEdit.js +105 -0
  193. package/src/tools/fsFind.js +128 -0
  194. package/src/tools/fsList.js +77 -0
  195. package/src/tools/fsMove.js +57 -0
  196. package/src/tools/fsRead.js +87 -0
  197. package/src/tools/fsSearch.js +198 -0
  198. package/src/tools/fsWrite.js +41 -0
  199. package/src/tools/gameAiBehaviorTree.js +208 -0
  200. package/src/tools/gameAnimationRig.js +194 -0
  201. package/src/tools/gameAssetFetcher.js +372 -0
  202. package/src/tools/gameAssetHarvester.js +210 -0
  203. package/src/tools/gameAudioSynth.js +267 -0
  204. package/src/tools/gameBuilder.js +886 -0
  205. package/src/tools/gameCanvasAudit.js +101 -0
  206. package/src/tools/gameCinematicSequencer.js +151 -0
  207. package/src/tools/gameDataForge.js +124 -0
  208. package/src/tools/gameDialogueTreeGen.js +166 -0
  209. package/src/tools/gameEconomyBalancer.js +161 -0
  210. package/src/tools/gameEntitySpawner.js +207 -0
  211. package/src/tools/gameLoreForge.js +153 -0
  212. package/src/tools/gameQuestArcBuilder.js +152 -0
  213. package/src/tools/gameSceneBuilder.js +158 -0
  214. package/src/tools/gameShaderForge.js +181 -0
  215. package/src/tools/gameTilemapGenerator.js +164 -0
  216. package/src/tools/gameUiHudBuilder.js +292 -0
  217. package/src/tools/gameVfxEmitterGen.js +108 -0
  218. package/src/tools/gameWebRuntimeInspector.js +91 -0
  219. package/src/tools/generateMediaViaApi.js +358 -0
  220. package/src/tools/gitExec.js +54 -0
  221. package/src/tools/godotAutomator.js +437 -0
  222. package/src/tools/manageLocalAiDependencies.js +220 -0
  223. package/src/tools/memoryWrite.js +99 -0
  224. package/src/tools/multiEdit.js +107 -0
  225. package/src/tools/palmierAutomator.js +104 -0
  226. package/src/tools/pdfReader.js +112 -0
  227. package/src/tools/persistentShell.js +148 -0
  228. package/src/tools/printer.js +316 -0
  229. package/src/tools/procTerm.js +91 -0
  230. package/src/tools/processList.js +52 -0
  231. package/src/tools/readNativeSkill.js +39 -0
  232. package/src/tools/registry.js +277 -0
  233. package/src/tools/resolveAutomator.js +102 -0
  234. package/src/tools/screenshot.js +75 -0
  235. package/src/tools/subagentOrchestrator.js +305 -0
  236. package/src/tools/sysRun.js +125 -0
  237. package/src/tools/todoWrite.js +75 -0
  238. package/src/tools/toolDispatch.js +127 -0
  239. package/src/tools/toolForge.js +124 -0
  240. package/src/tools/updatePlan.js +88 -0
  241. package/src/tools/viewImage.js +82 -0
  242. package/src/tools/visionInspector.js +154 -0
  243. package/src/tools/webFetch.js +74 -0
  244. package/src/tools/webSearch.js +82 -0
  245. package/src/tui/ask.js +164 -0
  246. package/src/tui/banner.js +158 -0
  247. package/src/tui/block.js +152 -0
  248. package/src/tui/chatRenderer.js +953 -0
  249. package/src/tui/completion.js +424 -0
  250. package/src/tui/dialogs.js +606 -0
  251. package/src/tui/diff.js +296 -0
  252. package/src/tui/history.js +135 -0
  253. package/src/tui/home.js +217 -0
  254. package/src/tui/invocation.js +105 -0
  255. package/src/tui/keys.js +443 -0
  256. package/src/tui/lineEditor.js +256 -0
  257. package/src/tui/overlay.js +256 -0
  258. package/src/tui/prompt.js +1258 -0
  259. package/src/tui/selectList.js +335 -0
  260. package/src/tui/stage.js +330 -0
  261. package/src/tui/stageSurface.js +609 -0
  262. package/src/tui/statusLine.js +254 -0
  263. package/src/tui/text.js +345 -0
  264. package/src/tui/theme.js +393 -0
  265. package/src/tui/toolDisplay.js +176 -0
  266. package/src/tui/transcript.js +235 -0
  267. package/src/tui/viewport.js +337 -0
  268. package/src/uncertainty.js +271 -0
  269. package/src/userSkills.js +265 -0
  270. package/src/utils/cli_ui.js +0 -0
  271. package/src/utils/inquirer.js +12 -0
  272. package/src/utils/paths.js +37 -0
  273. package/src/version.js +38 -0
  274. package/src/vfeTracker.js +220 -0
@@ -0,0 +1,124 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ import { causyneHome } from '../utils/paths.js';
5
+
6
+ const CUSTOM_TOOLS_DIR = path.join(causyneHome(), 'custom_tools');
7
+
8
+ export const toolForgeTool = {
9
+ schema: {
10
+ name: 'tool.forge',
11
+ description: 'Self-Evolution Engine: Write a new custom Javascript tool that will be permanently added to your capabilities. Use this when you lack a specific tool to accomplish a goal. The tool will be hot-reloaded instantly.',
12
+ parameters: {
13
+ type: 'object',
14
+ properties: {
15
+ toolName: {
16
+ type: 'string',
17
+ description: 'CamelCase name of the tool (e.g. "imageResizer", "pdfExtractor"). Must be alphanumeric without spaces.',
18
+ },
19
+ toolDescription: {
20
+ type: 'string',
21
+ description: 'Detailed description of what the tool does, so you know how to use it later.',
22
+ },
23
+ parametersSchema: {
24
+ type: 'string',
25
+ description: 'Stringified JSON schema of the arguments the tool accepts. E.g. {"type":"object","properties":{"filePath":{"type":"string"}},"required":["filePath"]}',
26
+ },
27
+ javascriptCode: {
28
+ type: 'string',
29
+ description: 'The actual Node.js code block for the execute function. MUST be an async function accepting (args, context). Must return an object like { success: true, data: ... }. DO NOT use `export` or `const toolName =`, just provide the raw function body or `async (args, context) => { ... }`.',
30
+ },
31
+ },
32
+ required: ['toolName', 'toolDescription', 'parametersSchema', 'javascriptCode'],
33
+ }
34
+ },
35
+ execute: async (args, context) => {
36
+ try {
37
+ const { toolName, toolDescription, parametersSchema, javascriptCode } = args;
38
+
39
+ // Validate name
40
+ if (!/^[a-zA-Z0-9_]+$/.test(toolName)) {
41
+ return { success: false, error: 'Invalid toolName. Use alphanumeric characters only.' };
42
+ }
43
+
44
+ // Ethical Safety Gate Layer 4: Block malicious tool names and descriptions
45
+ const BANNED_TOOL_NAMES = [
46
+ /keylog/i, /phish/i, /exploit/i, /malware/i, /trojan/i,
47
+ /ransomware/i, /rootkit/i, /backdoor/i, /ddos/i,
48
+ /credential.?harvest/i, /password.?steal/i, /brute.?force/i,
49
+ /crypto.?mine/i, /wallet.?drain/i, /spyware/i, /surveil/i
50
+ ];
51
+
52
+ for (const pattern of BANNED_TOOL_NAMES) {
53
+ if (pattern.test(toolName) || pattern.test(toolDescription)) {
54
+ return {
55
+ success: false,
56
+ error: 'Safety violation: Tool name or description indicates malicious intent. Causyne exists to make the world better.'
57
+ };
58
+ }
59
+ }
60
+
61
+
62
+ const SUBPROCESS_MODULE = "child_process";
63
+ const BANNED_TOOL_PATTERNS = [
64
+ /process\.kill\(/,
65
+ new RegExp(SUBPROCESS_MODULE),
66
+ new RegExp('require\\s*\\(\\s*[\'"]' + SUBPROCESS_MODULE + '[\'"]\\s*\\)'),
67
+ /fs\.(rm|rmdir)Sync.*recursive/i,
68
+ /fs\.writeFileSync\s*\(\s*['"]\/etc/,
69
+ /fs\.writeFileSync\s*\(\s*['"]C:\\\\Windows/i,
70
+ /stratum\+tcp/i,
71
+ /cryptonight|ethash|randomx/i,
72
+ /iohook|keypress|keylog/i,
73
+ /getUserMedia|MediaRecorder.*audio|MediaRecorder.*video/i,
74
+ /sqlmap|nikto|metasploit/i
75
+ ];
76
+
77
+ for (const pattern of BANNED_TOOL_PATTERNS) {
78
+ if (pattern.test(javascriptCode)) {
79
+ return {
80
+ success: false,
81
+ error: 'Safety violation: Tool code contains a banned pattern. Causyne cannot forge tools designed for harm.'
82
+ };
83
+ }
84
+ }
85
+
86
+ // Ensure directory exists
87
+ if (!fs.existsSync(CUSTOM_TOOLS_DIR)) {
88
+ fs.mkdirSync(CUSTOM_TOOLS_DIR, { recursive: true, mode: 0o700 });
89
+ }
90
+
91
+ const filePath = path.join(CUSTOM_TOOLS_DIR, `${toolName}.js`);
92
+
93
+ // Construct the ES Module file
94
+ const fileContent = `
95
+ // AUTOGENERATED CUSTOM TOOL: ${toolName}
96
+ // Generated at: ${new Date().toISOString()}
97
+
98
+ export const ${toolName}Tool = {
99
+ name: '${toolName}',
100
+ description: ${JSON.stringify(toolDescription)},
101
+ parameters: ${parametersSchema},
102
+ execute: async (args, context) => {
103
+ // LLM Generated Code Start
104
+ const llmFunction = ${javascriptCode.trim().startsWith('async') ? javascriptCode : `async (args, context) => { ${javascriptCode} }`};
105
+ return await llmFunction(args, context);
106
+ // LLM Generated Code End
107
+ }
108
+ };
109
+ `;
110
+
111
+ fs.writeFileSync(filePath, fileContent.trim());
112
+
113
+ return {
114
+ success: true,
115
+ message: `Successfully forged new tool '${toolName}'. It is saved to ${filePath}. It will be available on the next loop iteration.`
116
+ };
117
+ } catch (error) {
118
+ return {
119
+ success: false,
120
+ error: `Failed to forge tool: ${error.message}`
121
+ };
122
+ }
123
+ },
124
+ };
@@ -0,0 +1,88 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+
4
+ export const updatePlan = {
5
+ schema: {
6
+ name: 'update_plan',
7
+ description: 'Self-Correcting Trajectory Engine: Update specific tasks in your plan using delta operations without rewriting everything.',
8
+ parameters: {
9
+ type: 'object',
10
+ properties: {
11
+ action: {
12
+ type: 'string',
13
+ enum: ['read', 'ADD_TASK', 'REMOVE_TASK', 'MARK_COMPLETED', 'MARK_FAILED']
14
+ },
15
+ taskId: { type: 'string', description: 'ID of the task to modify' },
16
+ taskContent: { type: 'string', description: 'Content of the new task (if ADD_TASK)' },
17
+ failureReason: { type: 'string', description: 'REQUIRED if action is MARK_FAILED' }
18
+ },
19
+ required: ['action']
20
+ }
21
+ },
22
+
23
+ execute: async (args) => {
24
+ try {
25
+ const todoPath = path.resolve(process.cwd(), '.causyne_todos.json');
26
+ const mdPath = path.resolve(process.cwd(), 'AGI_PLAN.md');
27
+
28
+ let todos = [];
29
+ if (fs.existsSync(todoPath)) {
30
+ todos = JSON.parse(fs.readFileSync(todoPath, 'utf8'));
31
+ }
32
+
33
+ if (args.action === 'read') {
34
+ if (!fs.existsSync(mdPath)) return "No plan exists.";
35
+ return fs.readFileSync(mdPath, 'utf8');
36
+ }
37
+
38
+ if (args.action === 'MARK_FAILED' && !args.failureReason) {
39
+ return "Error: You MUST provide a failureReason when marking a task as failed.";
40
+ }
41
+
42
+ if (args.action === 'ADD_TASK') {
43
+ if (!args.taskId || !args.taskContent) return "Missing taskId or taskContent";
44
+ todos.push({ id: args.taskId, content: args.taskContent, status: 'pending' });
45
+ }
46
+ else if (args.action === 'REMOVE_TASK') {
47
+ todos = todos.filter(t => t.id !== args.taskId);
48
+ }
49
+ else if (args.action === 'MARK_COMPLETED') {
50
+ const t = todos.find(t => t.id === args.taskId);
51
+ if (t) t.status = 'completed';
52
+ }
53
+ else if (args.action === 'MARK_FAILED') {
54
+ const t = todos.find(t => t.id === args.taskId);
55
+ if (t) {
56
+ t.status = 'pending'; // Reset it
57
+ // Phase 2 AGI Upgrade: Auto-Pivot
58
+ todos.push({
59
+ id: `investigate_${args.taskId}`,
60
+ content: `Investigate failure of ${args.taskId}: ${args.failureReason}`,
61
+ status: 'in_progress'
62
+ });
63
+ }
64
+ }
65
+
66
+ // Sync JSON
67
+ fs.writeFileSync(todoPath, JSON.stringify(todos, null, 2), 'utf8');
68
+
69
+ // Sync MD
70
+ let mdContent = '# AGI Execution Plan\n\n';
71
+ for (const t of todos) {
72
+ let box = '[ ]';
73
+ if (t.status === 'in_progress') box = '[/]';
74
+ if (t.status === 'completed') box = '[x]';
75
+ mdContent += `- ${box} ${t.id}: ${t.content}\n`;
76
+ }
77
+ fs.writeFileSync(mdPath, mdContent, 'utf8');
78
+
79
+ if (args.action === 'MARK_FAILED') {
80
+ return `Task failed. Auto-pivot engaged. Added investigation task.`;
81
+ }
82
+
83
+ return "Plan delta updated successfully.";
84
+ } catch (error) {
85
+ return `Error updating plan: ${error.message}`;
86
+ }
87
+ }
88
+ };
@@ -0,0 +1,82 @@
1
+ import fs from 'fs/promises';
2
+ import { resolveUserPath } from '../utils/paths.js';
3
+ import { existsSync, statSync } from 'fs';
4
+ import path from 'path';
5
+ import os from 'os';
6
+ import { ensureCapability, loadCapabilityPackage } from '../provisioning/capabilityProvisioner.js';
7
+
8
+ export const viewImage = {
9
+ schema: {
10
+ name: 'view_image',
11
+ description: 'Multi-Modal Pre-Processing Engine. View an image file from disk. Automatically compresses huge images to save tokens. For text-only LLMs, it autonomously extracts text via OCR.',
12
+ parameters: {
13
+ type: 'object',
14
+ properties: {
15
+ path: { type: 'string', description: 'Absolute or relative path to the image file' },
16
+ extractTextOnly: { type: 'boolean', description: 'If true, skips Vision APIs and uses local OCR to read text from the image.' }
17
+ },
18
+ required: ['path']
19
+ }
20
+ },
21
+
22
+ execute: async (args, sandbox) => {
23
+ try {
24
+ const targetPath = resolveUserPath(args.path);
25
+ if (!existsSync(targetPath)) {
26
+ return { success: false, error: `Image not found at ${targetPath}` };
27
+ }
28
+
29
+ const stat = statSync(targetPath);
30
+ if (stat.size > 20 * 1024 * 1024) {
31
+ return { success: false, error: 'Image too large. Maximum raw size is 20MB.' };
32
+ }
33
+
34
+ // Phase 6 AGI Upgrade: OCR Fallback for Text-Only LLMs
35
+ const forceOcr = args.extractTextOnly || (sandbox && sandbox.llmSupportsVision === false);
36
+
37
+ if (forceOcr) {
38
+ const ocr = await ensureCapability('ocr');
39
+ if (!ocr.ok) return { success: false, error: ocr.reason, requiresConsent: ocr.requiresConsent };
40
+ const Tesseract = await loadCapabilityPackage('tesseract.js');
41
+
42
+ const worker = await Tesseract.createWorker('eng');
43
+ const { data: { text } } = await worker.recognize(targetPath);
44
+ await worker.terminate();
45
+
46
+ return { success: true, output: `[OCR FALLBACK] Extracted Text from Image:\n\n${text}` };
47
+ }
48
+
49
+ // Phase 6 AGI Upgrade: Dynamic Resizing & Format Normalization
50
+ let processedBuffer;
51
+ let mimeType = 'image/jpeg';
52
+
53
+ try {
54
+ // sharp already lives in the Cortex tree as a pinned override, so it is
55
+ // loaded from there rather than installed a second time.
56
+ const sharp = await loadCapabilityPackage('sharp');
57
+ processedBuffer = await sharp(targetPath)
58
+ .resize({ width: 1024, height: 1024, fit: 'inside', withoutEnlargement: true })
59
+ .jpeg({ quality: 85 })
60
+ .toBuffer();
61
+ } catch (e) {
62
+ // Fallback if sharp is missing (return raw buffer but warn)
63
+ processedBuffer = await fs.readFile(targetPath);
64
+ const ext = path.extname(targetPath).toLowerCase();
65
+ if (ext === '.png') mimeType = 'image/png';
66
+ else if (ext === '.webp') mimeType = 'image/webp';
67
+ else if (ext === '.gif') mimeType = 'image/gif';
68
+ }
69
+
70
+ const base64 = processedBuffer.toString('base64');
71
+
72
+ return {
73
+ _is_image_marker: true,
74
+ mimeType,
75
+ base64,
76
+ filename: path.basename(targetPath)
77
+ };
78
+ } catch (error) {
79
+ return { success: false, error: `Error viewing image: ${error.message}` };
80
+ }
81
+ }
82
+ };
@@ -0,0 +1,154 @@
1
+ import fs from 'fs/promises';
2
+ import fsSync from 'fs';
3
+ import path from 'path';
4
+ import { execFile } from 'child_process';
5
+ import { promisify } from 'util';
6
+
7
+ import { ensureCapability, loadCapabilityPackage } from '../provisioning/capabilityProvisioner.js';
8
+
9
+ const execFileAsync = promisify(execFile);
10
+
11
+ // Helper: Sovereign Workspace Buffer to prevent /tmp/ boundary errors
12
+ function getWorkspaceTempDir() {
13
+ const dir = path.join(process.cwd(), '.tmp_causyne_3d');
14
+ if (!fsSync.existsSync(dir)) {
15
+ fsSync.mkdirSync(dir, { recursive: true });
16
+ }
17
+ return dir;
18
+ }
19
+
20
+ export const visionInspector = {
21
+ schema: {
22
+ name: 'vision.inspect_ui',
23
+ description: 'Captures live desktop (macOS/Windows) or mobile (Android via ADB) screenshots directly into the local workspace buffer (.tmp_causyne_3d/) and extracts spatial bounding box coordinates for visual layout verification, LCP debugging, and UI automation.',
24
+ parameters: {
25
+ type: 'object',
26
+ properties: {
27
+ target: {
28
+ type: 'string',
29
+ enum: ['desktop', 'android_adb'],
30
+ description: 'Target device screen to capture: desktop (OS GUI) or android_adb (connected mobile screen).'
31
+ },
32
+ prompt: { type: 'string', description: 'The verification prompt describing what UI element, visual bug, alignment, or LCP state is being audited.' },
33
+ deviceSerial: { type: 'string', description: 'Optional Android ADB device serial when target is android_adb.' }
34
+ },
35
+ required: ['target', 'prompt']
36
+ }
37
+ },
38
+
39
+ async execute(args, context = {}) {
40
+ try {
41
+ const target = args.target || 'desktop';
42
+ const prompt = args.prompt || 'Inspect UI spatial layout';
43
+ const tempDir = getWorkspaceTempDir();
44
+ const timestamp = Date.now();
45
+ const destPath = path.join(tempDir, `ui_inspect_${target}_${timestamp}.png`);
46
+
47
+ if (target === 'android_adb') {
48
+ const adbArgs = [];
49
+ if (args.deviceSerial) adbArgs.push('-s', args.deviceSerial);
50
+ adbArgs.push('shell', 'screencap', '-p');
51
+
52
+ try {
53
+ const { stdout } = await execFileAsync('adb', adbArgs, { encoding: 'buffer', maxBuffer: 20 * 1024 * 1024 });
54
+ // Handle CRLF on Windows ADB pipes
55
+ let cleanBuffer = stdout;
56
+ if (process.platform === 'win32') {
57
+ cleanBuffer = Buffer.from(stdout.toString('binary').replace(/\r\n/g, '\n'), 'binary');
58
+ }
59
+ await fs.writeFile(destPath, cleanBuffer);
60
+ } catch (adbErr) {
61
+ return {
62
+ success: false,
63
+ error: `ADB Mobile Vision Capture Failed: ${adbErr.message}. Ensure device is connected via ADB USB/WiFi.`
64
+ };
65
+ }
66
+ } else {
67
+ // Desktop OS Screen Capture
68
+ try {
69
+ if (process.platform === 'darwin') {
70
+ await execFileAsync('screencapture', ['-x', destPath]);
71
+ } else if (process.platform === 'win32') {
72
+ const psCmd = `Add-Type -AssemblyName System.Windows.Forms,System.Drawing; $screen = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds; $bitmap = New-Object System.Drawing.Bitmap $screen.Width, $screen.Height; $graphics = [System.Drawing.Graphics]::FromImage($bitmap); $graphics.CopyFromScreen($screen.Location, [System.Drawing.Point]::Empty, $screen.Size); $bitmap.Save('${destPath.replace(/\\/g, '\\\\')}', [System.Drawing.Imaging.ImageFormat]::Png); $graphics.Dispose(); $bitmap.Dispose();`;
73
+ await execFileAsync('powershell.exe', ['-NoLogo', '-NoProfile', '-Command', psCmd]);
74
+ } else {
75
+ // macOS and Windows capture natively above; only this branch needs
76
+ // the provisioned package.
77
+ const vision = await ensureCapability('vision');
78
+ if (!vision.ok) throw new Error(vision.reason);
79
+ const screenshotDesktop = await loadCapabilityPackage('screenshot-desktop');
80
+ await screenshotDesktop({ filename: destPath });
81
+ }
82
+ } catch (captureErr) {
83
+
84
+ if (captureErr.message && (captureErr.message.includes('could not create image from display') || captureErr.message.includes('No display') || captureErr.message.includes('xclip'))) {
85
+ // Check if any existing buffer image exists in tempDir to inspect
86
+ const existingFiles = fsSync.readdirSync(tempDir).filter(f => f.endsWith('.png'));
87
+ if (existingFiles.length > 0) {
88
+ const fallbackFile = path.join(tempDir, existingFiles[existingFiles.length - 1]);
89
+ return {
90
+ success: true,
91
+ output: JSON.stringify({
92
+ status: 'Headless environment detected: GUI capture restricted. Returned latest buffered workspace visual frame.',
93
+ target_device: target,
94
+ verification_prompt: prompt,
95
+ filepath: fallbackFile,
96
+ workspace_boundary_safe: true,
97
+ headless_notice: captureErr.message
98
+ }, null, 2)
99
+ };
100
+ }
101
+ return {
102
+ success: true,
103
+ output: JSON.stringify({
104
+ status: 'Live GUI capture is unavailable in this desktop session. Connect an active display or use an ADB mobile target.',
105
+ target_device: target,
106
+ verification_prompt: prompt,
107
+ headless_notice: captureErr.message
108
+ }, null, 2)
109
+ };
110
+ }
111
+ throw captureErr;
112
+ }
113
+ }
114
+
115
+ // Check spatial OCR / bounding box extraction
116
+ let textMap = '';
117
+ try {
118
+ const ocr = await ensureCapability('ocr');
119
+ if (!ocr.ok) throw new Error(ocr.reason);
120
+ const Tesseract = await loadCapabilityPackage('tesseract.js');
121
+ const worker = await Tesseract.createWorker('eng');
122
+ const { data: { words } } = await worker.recognize(destPath);
123
+ await worker.terminate();
124
+
125
+ const confidentWords = (words || []).filter(w => w.confidence > 75).slice(0, 30);
126
+ if (confidentWords.length > 0) {
127
+ textMap = confidentWords.map(w => {
128
+ const centerX = Math.floor((w.bbox.x0 + w.bbox.x1) / 2);
129
+ const centerY = Math.floor((w.bbox.y0 + w.bbox.y1) / 2);
130
+ return `- [${w.text}] X:${centerX}, Y:${centerY}`;
131
+ }).join('\n');
132
+ }
133
+ } catch (ocrErr) {
134
+ textMap = `[OCR Text Bounding extraction skipped: ${ocrErr.message}]`;
135
+ }
136
+
137
+ // Route notification to mobile app (`AgentScreen.kt`)
138
+
139
+ return {
140
+ success: true,
141
+ output: JSON.stringify({
142
+ status: 'Visual inspection frame captured cleanly inside workspace buffer',
143
+ target_device: target,
144
+ verification_prompt: prompt,
145
+ filepath: destPath,
146
+ workspace_boundary_safe: true,
147
+ detected_spatial_elements: textMap || 'No confident OCR text tokens detected.'
148
+ }, null, 2)
149
+ };
150
+ } catch (e) {
151
+ return { success: false, error: e.message };
152
+ }
153
+ }
154
+ };
@@ -0,0 +1,74 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import os from 'os';
4
+
5
+ // Phase 3 AGI Upgrade: HTML Cleanup to Markdown
6
+ function htmlToText(html) {
7
+ // AGI Optimization: Aggressively strip scripts, styles, svg, and tags
8
+ let text = html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
9
+ text = text.replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, '');
10
+ text = text.replace(/<svg\b[^<]*(?:(?!<\/svg>)<[^<]*)*<\/svg>/gi, '');
11
+ text = text.replace(/<[^>]+>/g, ' '); // Strip HTML tags
12
+ text = text.replace(/&nbsp;/g, ' '); // Decode basic entities
13
+ text = text.replace(/\s{2,}/g, ' '); // Normalize spaces
14
+ text = text.replace(/\n\s*\n/g, '\n\n'); // Normalize line breaks
15
+ return text.trim();
16
+ }
17
+
18
+ export const webFetch = {
19
+ schema: {
20
+ name: 'web.fetch',
21
+ description: 'Make HTTP requests. Automatically strips raw HTML into clean text to protect Context Window.',
22
+ parameters: {
23
+ type: 'object',
24
+ properties: {
25
+ url: { type: 'string' },
26
+ method: { type: 'string' },
27
+ headers: { type: 'object' },
28
+ body: { type: 'string' },
29
+ outputFile: { type: 'string', description: 'If provided, saves as a binary file instead of returning text' }
30
+ },
31
+ required: ['url']
32
+ }
33
+ },
34
+ async execute(args) {
35
+ try {
36
+ const options = {
37
+ method: args.method || 'GET',
38
+ headers: {
39
+ 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/120.0.0.0 Safari/537.36',
40
+ ...args.headers
41
+ }
42
+ };
43
+
44
+ if (args.body) options.body = args.body;
45
+
46
+ const response = await fetch(args.url, options);
47
+
48
+ if (args.outputFile) {
49
+ const target = args.outputFile.replace(/^~\//, os.homedir() + '/');
50
+ const buffer = await response.arrayBuffer();
51
+ await fs.writeFile(target, Buffer.from(buffer));
52
+ return { success: true, output: `Downloaded ${buffer.byteLength} bytes to ${args.outputFile}`, status: response.status };
53
+ }
54
+
55
+ const text = await response.text();
56
+
57
+ // Phase 3 AGI Upgrade: Clean HTML unless it's an API JSON response
58
+ let cleanOutput = text;
59
+ const contentType = response.headers.get('content-type') || '';
60
+ if (contentType.includes('text/html')) {
61
+ cleanOutput = htmlToText(text);
62
+ }
63
+
64
+ // Strict Context Paging Protection
65
+ if (cleanOutput.length > 50000) {
66
+ cleanOutput = cleanOutput.substring(0, 50000) + '\n\n[... OUTPUT TRUNCATED TO 50KB ...]';
67
+ }
68
+
69
+ return { success: true, output: cleanOutput, status: response.status };
70
+ } catch (e) {
71
+ return { success: false, error: e.message };
72
+ }
73
+ }
74
+ };
@@ -0,0 +1,82 @@
1
+ export const webSearch = {
2
+ schema: {
3
+ name: 'web_search',
4
+ description: 'High-Precision SERP Router. Searches the web and extracts top organic results.',
5
+ parameters: {
6
+ type: 'object',
7
+ properties: {
8
+ query: {
9
+ type: 'string',
10
+ description: 'The search query.'
11
+ }
12
+ },
13
+ required: ['query']
14
+ }
15
+ },
16
+
17
+ execute: async (args) => {
18
+ try {
19
+ // Phase 7 AGI Upgrade: Zero-Dependency Native Fetch Scraper
20
+ // Skipping Google's aggressive 429 Blocks by utilizing Yahoo Search HTML parsing.
21
+ const url = 'https://search.yahoo.com/search?p=' + encodeURIComponent(args.query);
22
+
23
+ const response = await fetch(url, {
24
+ headers: {
25
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
26
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
27
+ 'Accept-Language': 'en-US,en;q=0.5'
28
+ }
29
+ });
30
+
31
+ if (!response.ok) {
32
+ throw new Error(`HTTP Error ${response.status}`);
33
+ }
34
+
35
+ const html = await response.text();
36
+ const results = [];
37
+
38
+ // Robust Regex to extract Yahoo organic results
39
+ const regex = /<div class=\"compTitle[^>]*>.*?<h3[^>]*>.*?<a[^>]*href=\"([^\"]+)\"[^>]*>(.*?)<\/a>.*?<\/h3>.*?<div class=\"compText[^>]*>(.*?)<\/div>/gs;
40
+
41
+ let match;
42
+ while ((match = regex.exec(html)) !== null && results.length < 8) {
43
+ let link = match[1];
44
+
45
+ // Yahoo heavily redirects via RU=..., decode it to get the raw clean URL
46
+ if (link.includes('RU=')) {
47
+ const ruMatch = link.match(/RU=([^/]+)\//);
48
+ if (ruMatch) link = decodeURIComponent(ruMatch[1]);
49
+ }
50
+
51
+ // Skip sponsored Bing/Yahoo Ads
52
+ if (link.includes('bing.com/aclick') || link.includes('yahoo.com/yhs/')) {
53
+ continue;
54
+ }
55
+
56
+ results.push({
57
+ url: link,
58
+ title: match[2].replace(/<[^>]+>/g, '').trim(),
59
+ snippet: match[3].replace(/<[^>]+>/g, '').trim()
60
+ });
61
+ }
62
+
63
+ if (results.length === 0) {
64
+ return { success: true, output: "No organic results found. Try using web.fetch on known direct domains." };
65
+ }
66
+
67
+ let outputString = `🔍 SERP Results for "${args.query}":\n\n`;
68
+ outputString += `[TOP WEB RESULTS]\n`;
69
+ results.forEach((r, idx) => {
70
+ outputString += `${idx + 1}. ${r.title}\n URL: ${r.url}\n Snippet: ${r.snippet}\n\n`;
71
+ });
72
+
73
+ return { success: true, output: outputString.trim() };
74
+
75
+ } catch (error) {
76
+ return {
77
+ success: false,
78
+ error: `Search Engine Blocked Request: ${error.message}. Do NOT guess random API URLs. Instead, use the web_fetch tool directly on known sites (e.g. finance.yahoo.com, coinmarketcap.com, wikipedia.org).`
79
+ };
80
+ }
81
+ }
82
+ };