clarity-ai 6.4.1 → 6.5.1
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/CHANGELOG.md +17 -0
- package/LICENSE +12 -0
- package/README.md +3 -9
- package/package.json +9 -3
- package/requirements.txt +3 -0
- package/scripts/postinstall.js +19 -42
- package/space_app.py +45 -0
- package/src/config/keys.js +4 -4
- package/src/providers/index.js +26 -11
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
+
## 6.5.0 (2026-06-06)
|
|
6
|
+
|
|
7
|
+
### Closed Source + Space Proxy
|
|
8
|
+
- All tokens removed from source code — zero hardcoded secrets
|
|
9
|
+
- `LICENSE`: Proprietary, all rights reserved (`UNLICENSED`)
|
|
10
|
+
- Provider now points to `Clarity-main` Space endpoint (`*.hf.space`) instead of `api-inference.huggingface.co` — fixes DNS resolution issues on Termux/Android
|
|
11
|
+
- Clarity-main Space runs inference proxy: forwards to HF Inference API using internal `HF_TOKEN` secret
|
|
12
|
+
- No API key required from CLI — works out of the box on any network
|
|
13
|
+
- Space app: `space_app.py` — Gradio + FastAPI, `/v1/chat/completions` streaming, `/main-data` data endpoint
|
|
14
|
+
|
|
15
|
+
## 6.4.2 (2026-06-06)
|
|
16
|
+
|
|
17
|
+
### Keyless Clarity Flash
|
|
18
|
+
- HuggingFace provider no longer requires API key
|
|
19
|
+
- Built-in HF token for Clarity Flash model — works out of the box, no setup
|
|
20
|
+
- Can still override with `HF_TOKEN` env var or `/keys huggingface <token>`
|
|
21
|
+
|
|
5
22
|
## 6.4.1 (2026-06-06)
|
|
6
23
|
|
|
7
24
|
### Clarity Flash 14B Model
|
package/LICENSE
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
CLARITY AI — Proprietary Software
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Universal-618
|
|
4
|
+
|
|
5
|
+
All rights reserved.
|
|
6
|
+
|
|
7
|
+
This software and its source code are proprietary and confidential.
|
|
8
|
+
Unauthorized copying, modification, distribution, or use of this
|
|
9
|
+
software, via any medium, is strictly prohibited without prior
|
|
10
|
+
written permission from the copyright holder.
|
|
11
|
+
|
|
12
|
+
This software is provided "as is", without warranty of any kind.
|
package/README.md
CHANGED
|
@@ -103,16 +103,10 @@ clarity /bash ls -la
|
|
|
103
103
|
| Gemini 2.0 Flash | Google | 32K (fast) |
|
|
104
104
|
| DeepSeek R1 Free | OpenRouter | 128K |
|
|
105
105
|
|
|
106
|
-
##
|
|
106
|
+
## Architecture
|
|
107
107
|
|
|
108
|
-
|
|
109
|
-
|---|---|---|---|
|
|
110
|
-
| Groq | ✓ | ✓ | 1 (fastest) |
|
|
111
|
-
| Google Gemini | ✓ | ✓ | 2 |
|
|
112
|
-
| HuggingFace (Clarity Flash) | Needs HF_TOKEN | ✓ | 3 |
|
|
113
|
-
| DeepSeek | Cheap | ✓ | 4 |
|
|
114
|
-
| OpenRouter | ✓ | ✓ | 5 |
|
|
108
|
+
Clarity Flash 14B is served via `Clarity-main` HF Space — a streaming inference proxy at `*.hf.space/v1/chat/completions`. No API keys needed.
|
|
115
109
|
|
|
116
110
|
## License
|
|
117
111
|
|
|
118
|
-
|
|
112
|
+
Proprietary — all rights reserved. See [LICENSE](LICENSE).
|
package/package.json
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clarity-ai",
|
|
3
|
-
"version": "6.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "6.5.1",
|
|
4
|
+
"description": "CLARITY — terminal AI agent with Clarity Flash 14B",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"clarity": "bin/clarity.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
-
"start": "node bin/clarity.js"
|
|
10
|
+
"start": "node bin/clarity.js",
|
|
11
|
+
"postinstall": "node scripts/postinstall.js"
|
|
11
12
|
},
|
|
12
13
|
"engines": {
|
|
13
14
|
"node": ">=18.0.0"
|
|
14
15
|
},
|
|
16
|
+
"license": "UNLICENSED",
|
|
17
|
+
"private": false,
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public"
|
|
20
|
+
},
|
|
15
21
|
"dependencies": {
|
|
16
22
|
"ink": "^5",
|
|
17
23
|
"react": "^18",
|
package/requirements.txt
ADDED
package/scripts/postinstall.js
CHANGED
|
@@ -1,59 +1,36 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import chalk from 'chalk';
|
|
4
|
-
|
|
5
|
-
const GRADIENT = gradient(['#00d2ff', '#7b2ff7']);
|
|
6
|
-
|
|
7
|
-
try {
|
|
8
|
-
const text = figlet.textSync('CLARITY', { font: 'ANSI Shadow' });
|
|
9
|
-
console.log(GRADIENT(text));
|
|
10
|
-
} catch {
|
|
11
|
-
console.log(GRADIENT('CLARITY'));
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const nodeVersion = process.versions.node;
|
|
15
|
-
const [major] = nodeVersion.split('.').map(Number);
|
|
16
|
-
const W = process.stdout.columns || 80;
|
|
17
|
-
const line = '═'.repeat(W - 4);
|
|
1
|
+
import { existsSync, chmodSync, writeFileSync, unlinkSync, lstatSync } from 'fs';
|
|
2
|
+
import { resolve } from 'path';
|
|
18
3
|
|
|
4
|
+
const nodeVer = process.versions.node;
|
|
5
|
+
const [major] = nodeVer.split('.').map(Number);
|
|
19
6
|
if (major < 18) {
|
|
20
|
-
console.error();
|
|
21
|
-
console.error(
|
|
22
|
-
console.error(chalk.hex('#ff4466')(` ║ ✗ Node.js 18+ required. You have v${nodeVersion}`));
|
|
23
|
-
console.error(chalk.hex('#ffcc00')(` ║ Termux: pkg install nodejs-lts`));
|
|
24
|
-
console.error(chalk.hex('#ff4466')(` ╚${line}╝`));
|
|
25
|
-
console.error();
|
|
7
|
+
console.error('\n \u2717 Node.js 18+ required. You have v' + nodeVer);
|
|
8
|
+
console.error(' Termux: pkg install nodejs-lts\n');
|
|
26
9
|
process.exit(1);
|
|
27
10
|
}
|
|
28
11
|
|
|
29
12
|
const isTermux = process.env.PREFIX?.includes('com.termux');
|
|
13
|
+
const W = process.stdout.columns || 80;
|
|
14
|
+
const line = '\u2500'.repeat(Math.min(W - 4, 60));
|
|
30
15
|
|
|
31
|
-
console.log();
|
|
32
|
-
console.log(
|
|
33
|
-
console.log(
|
|
34
|
-
console.log(
|
|
35
|
-
console.log(chalk.hex('#00ff88')(` ╚${line}╝`));
|
|
36
|
-
console.log();
|
|
37
|
-
console.log(chalk.hex('#666888')(" Run 'clarity init' to configure your AI keys and get started."));
|
|
16
|
+
console.log(`\n \u250C${line}\u2510`);
|
|
17
|
+
console.log(` \u2502 CLARITY installed`);
|
|
18
|
+
console.log(` \u2502 Run: clarity init`);
|
|
19
|
+
console.log(` \u2514${line}\u2518\n`);
|
|
38
20
|
|
|
39
21
|
const binDir = process.env.npm_config_prefix ? `${process.env.npm_config_prefix}/bin` : null;
|
|
40
22
|
if (isTermux && binDir) {
|
|
41
|
-
const { existsSync, writeFileSync, chmodSync, unlinkSync, lstatSync } = await import('fs');
|
|
42
|
-
const { resolve } = await import('path');
|
|
43
23
|
const symlinkPath = resolve(binDir, 'clarity');
|
|
44
|
-
|
|
45
24
|
try {
|
|
46
25
|
if (existsSync(symlinkPath)) {
|
|
47
26
|
const stat = lstatSync(symlinkPath);
|
|
48
|
-
if (stat.isSymbolicLink())
|
|
49
|
-
unlinkSync(symlinkPath);
|
|
50
|
-
}
|
|
27
|
+
if (stat.isSymbolicLink()) unlinkSync(symlinkPath);
|
|
51
28
|
}
|
|
52
|
-
const
|
|
53
|
-
|
|
29
|
+
const pkgDir = process.env.PREFIX
|
|
30
|
+
? `${process.env.PREFIX}/lib/node_modules/clarity-ai`
|
|
31
|
+
: resolve(process.cwd());
|
|
32
|
+
writeFileSync(symlinkPath, `#!/data/data/com.termux/files/usr/bin/bash\nexec node "${pkgDir}/bin/clarity.js" "$@"\n`);
|
|
54
33
|
chmodSync(symlinkPath, '755');
|
|
55
|
-
console.log(
|
|
56
|
-
} catch
|
|
57
|
-
console.error(chalk.hex('#ff4466')(' ✗ Failed to create Termux wrapper:'), e.message);
|
|
58
|
-
}
|
|
34
|
+
console.log(' \u2713 Termux wrapper created');
|
|
35
|
+
} catch {}
|
|
59
36
|
}
|
package/space_app.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import os, json, asyncio
|
|
2
|
+
import httpx
|
|
3
|
+
from fastapi import FastAPI, Request
|
|
4
|
+
from fastapi.responses import StreamingResponse, JSONResponse
|
|
5
|
+
from contextlib import asynccontextmanager
|
|
6
|
+
|
|
7
|
+
HF_TOKEN = os.environ.get('HF_TOKEN', '')
|
|
8
|
+
MODEL = os.environ.get('HF_MODEL', 'Universal-618/Clarity-flash-weights')
|
|
9
|
+
API = f'https://api-inference.huggingface.co/models/{MODEL}/v1/chat/completions'
|
|
10
|
+
HEADERS = {'Authorization': f'Bearer {HF_TOKEN}', 'Content-Type': 'application/json'}
|
|
11
|
+
|
|
12
|
+
app = FastAPI()
|
|
13
|
+
|
|
14
|
+
@app.post('/v1/chat/completions')
|
|
15
|
+
async def proxy(request: Request):
|
|
16
|
+
body = await request.json()
|
|
17
|
+
body['model'] = MODEL
|
|
18
|
+
stream = body.get('stream', True)
|
|
19
|
+
body['stream'] = stream
|
|
20
|
+
async with httpx.AsyncClient(timeout=120) as client:
|
|
21
|
+
resp = await client.post(API, headers=HEADERS, json=body)
|
|
22
|
+
if resp.status_code != 200:
|
|
23
|
+
return JSONResponse({'error': await resp.aread()}, status_code=resp.status_code)
|
|
24
|
+
if stream:
|
|
25
|
+
return StreamingResponse(resp.aiter_lines(), media_type='text/event-stream', headers={
|
|
26
|
+
'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'X-Accel-Buffering': 'no'
|
|
27
|
+
})
|
|
28
|
+
return resp.json()
|
|
29
|
+
|
|
30
|
+
@app.get('/main-data/{path:path}')
|
|
31
|
+
async def main_data(path: str):
|
|
32
|
+
path = path or 'index.json'
|
|
33
|
+
fp = f'/data/{path}'
|
|
34
|
+
if not os.path.exists(fp):
|
|
35
|
+
return JSONResponse({'error': 'not found'}, status_code=404)
|
|
36
|
+
with open(fp) as f:
|
|
37
|
+
return JSONResponse(json.load(f))
|
|
38
|
+
|
|
39
|
+
@app.get('/')
|
|
40
|
+
async def root():
|
|
41
|
+
return {'status': 'ok', 'model': MODEL, 'docs': '/v1/chat/completions'}
|
|
42
|
+
|
|
43
|
+
if __name__ == '__main__':
|
|
44
|
+
import uvicorn
|
|
45
|
+
uvicorn.run(app, host='0.0.0.0', port=7860)
|
package/src/config/keys.js
CHANGED
|
@@ -23,10 +23,10 @@ export function setKey(provider, key) {
|
|
|
23
23
|
export function getKey(provider) {
|
|
24
24
|
try {
|
|
25
25
|
const keys = JSON.parse(readFileSync(KEYS_PATH, 'utf-8'));
|
|
26
|
-
|
|
27
|
-
} catch {
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
if (keys[provider]) return keys[provider];
|
|
27
|
+
} catch {}
|
|
28
|
+
const envKey = process.env[provider.toUpperCase() + '_API_KEY'] || process.env.HF_TOKEN;
|
|
29
|
+
return envKey || null;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
export function hasKey(provider) {
|
package/src/providers/index.js
CHANGED
|
@@ -2,17 +2,26 @@ import { getKey } from '../config/keys.js';
|
|
|
2
2
|
import { streamResponse } from './streaming.js';
|
|
3
3
|
import { parseErrorResponse } from './errors.js';
|
|
4
4
|
|
|
5
|
+
const SPACES = [
|
|
6
|
+
'https://universal-618-clarity-main.hf.space',
|
|
7
|
+
'https://universal-618-clarity-2.hf.space',
|
|
8
|
+
'https://universal-618-clarity-3.hf.space',
|
|
9
|
+
'https://universal-618-clarity-4.hf.space',
|
|
10
|
+
'https://universal-618-clarity-5.hf.space',
|
|
11
|
+
'https://universal-618-clarity-6.hf.space',
|
|
12
|
+
];
|
|
13
|
+
|
|
5
14
|
const PROVIDERS = {
|
|
6
15
|
huggingface: {
|
|
7
|
-
|
|
16
|
+
endpoints: SPACES.map(s => s + '/v1/chat/completions'),
|
|
8
17
|
name: 'huggingface',
|
|
9
18
|
},
|
|
10
19
|
groq: {
|
|
11
|
-
|
|
20
|
+
endpoints: ['https://api.groq.com/openai/v1/chat/completions'],
|
|
12
21
|
name: 'groq',
|
|
13
22
|
},
|
|
14
23
|
openrouter: {
|
|
15
|
-
|
|
24
|
+
endpoints: ['https://openrouter.ai/api/v1/chat/completions'],
|
|
16
25
|
name: 'openrouter',
|
|
17
26
|
},
|
|
18
27
|
};
|
|
@@ -40,20 +49,26 @@ export async function* callAI(providerName, model, messages, options = {}) {
|
|
|
40
49
|
body.tool_choice = 'auto';
|
|
41
50
|
}
|
|
42
51
|
|
|
43
|
-
let endpoint = provider.endpoint;
|
|
44
52
|
const extraHeaders = {};
|
|
45
|
-
if (providerName === '
|
|
46
|
-
endpoint = provider.endpoint + '/' + modelName + '/v1/chat/completions';
|
|
47
|
-
if (key) extraHeaders['Authorization'] = 'Bearer ' + key;
|
|
48
|
-
} else if (providerName === 'openrouter') {
|
|
53
|
+
if (providerName === 'openrouter') {
|
|
49
54
|
extraHeaders['HTTP-Referer'] = 'https://clarity-ai.local';
|
|
50
55
|
extraHeaders['X-Title'] = 'CLARITY AI';
|
|
51
56
|
}
|
|
52
57
|
|
|
53
|
-
|
|
54
|
-
for
|
|
55
|
-
|
|
58
|
+
let lastErr;
|
|
59
|
+
for (const endpoint of provider.endpoints) {
|
|
60
|
+
try {
|
|
61
|
+
const stream = streamResponse(endpoint, body, key || 'none', extraHeaders, options.signal);
|
|
62
|
+
for await (const event of stream) {
|
|
63
|
+
yield event;
|
|
64
|
+
}
|
|
65
|
+
return;
|
|
66
|
+
} catch (err) {
|
|
67
|
+
lastErr = err;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
56
70
|
}
|
|
71
|
+
throw lastErr;
|
|
57
72
|
}
|
|
58
73
|
|
|
59
74
|
export async function callAISync(providerName, model, messages, options = {}) {
|