chainlesschain 0.47.8 → 0.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/chainlesschain.js +0 -0
- package/package.json +10 -8
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AppLayout-6SPt_8Y_.js → AppLayout-Rvi759IS.js} +1 -1
- package/src/assets/web-panel/assets/Dashboard-BS-tzGNj.css +1 -0
- package/src/assets/web-panel/assets/{Dashboard-Br7kCwKJ.js → Dashboard-DBhFxXYQ.js} +2 -2
- package/src/assets/web-panel/assets/{index-tN-8TosE.js → index-uL0cZ8N_.js} +2 -2
- package/src/assets/web-panel/index.html +2 -2
- package/src/commands/activitypub.js +533 -0
- package/src/commands/codegen.js +303 -0
- package/src/commands/collab.js +482 -0
- package/src/commands/compliance.js +597 -6
- package/src/commands/crosschain.js +382 -0
- package/src/commands/dbevo.js +388 -0
- package/src/commands/dev.js +411 -0
- package/src/commands/federation.js +427 -0
- package/src/commands/fusion.js +332 -0
- package/src/commands/governance.js +505 -0
- package/src/commands/hardening.js +110 -0
- package/src/commands/incentive.js +373 -0
- package/src/commands/inference.js +304 -0
- package/src/commands/infra.js +361 -0
- package/src/commands/kg.js +371 -0
- package/src/commands/marketplace.js +326 -0
- package/src/commands/matrix.js +283 -0
- package/src/commands/mcp.js +441 -18
- package/src/commands/nlprog.js +329 -0
- package/src/commands/nostr.js +196 -7
- package/src/commands/ops.js +408 -0
- package/src/commands/perception.js +385 -0
- package/src/commands/pqc.js +34 -0
- package/src/commands/privacy.js +345 -0
- package/src/commands/quantization.js +280 -0
- package/src/commands/recommend.js +336 -0
- package/src/commands/reputation.js +349 -0
- package/src/commands/runtime.js +500 -0
- package/src/commands/sla.js +352 -0
- package/src/commands/social.js +265 -0
- package/src/commands/stress.js +252 -0
- package/src/commands/tech.js +268 -0
- package/src/commands/tenant.js +576 -0
- package/src/commands/trust.js +366 -0
- package/src/harness/mcp-client.js +330 -54
- package/src/index.js +114 -0
- package/src/lib/activitypub-bridge.js +623 -0
- package/src/lib/aiops.js +523 -0
- package/src/lib/autonomous-developer.js +524 -0
- package/src/lib/code-agent.js +442 -0
- package/src/lib/collaboration-governance.js +556 -0
- package/src/lib/community-governance.js +649 -0
- package/src/lib/compliance-framework-reporter.js +600 -0
- package/src/lib/content-recommendation.js +600 -0
- package/src/lib/cross-chain.js +669 -0
- package/src/lib/dbevo.js +669 -0
- package/src/lib/decentral-infra.js +445 -0
- package/src/lib/federation-hardening.js +587 -0
- package/src/lib/hardening-manager.js +409 -0
- package/src/lib/inference-network.js +407 -0
- package/src/lib/knowledge-graph.js +530 -0
- package/src/lib/matrix-bridge.js +252 -0
- package/src/lib/mcp-client.js +3 -0
- package/src/lib/mcp-registry.js +347 -0
- package/src/lib/mcp-scaffold.js +385 -0
- package/src/lib/multimodal.js +698 -0
- package/src/lib/nl-programming.js +595 -0
- package/src/lib/nostr-bridge.js +214 -38
- package/src/lib/perception.js +500 -0
- package/src/lib/pqc-manager.js +141 -9
- package/src/lib/privacy-computing.js +575 -0
- package/src/lib/protocol-fusion.js +535 -0
- package/src/lib/quantization.js +362 -0
- package/src/lib/reputation-optimizer.js +509 -0
- package/src/lib/skill-marketplace.js +397 -0
- package/src/lib/sla-manager.js +484 -0
- package/src/lib/social-graph.js +408 -0
- package/src/lib/stix-parser.js +167 -0
- package/src/lib/stress-tester.js +383 -0
- package/src/lib/tech-learning-engine.js +651 -0
- package/src/lib/tenant-saas.js +831 -0
- package/src/lib/threat-intel.js +268 -0
- package/src/lib/token-incentive.js +513 -0
- package/src/lib/topic-classifier.js +400 -0
- package/src/lib/trust-security.js +473 -0
- package/src/lib/ueba.js +403 -0
- package/src/lib/universal-runtime.js +771 -0
- package/src/assets/web-panel/assets/Dashboard-CKeMmCoT.css +0 -1
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model Quantization — CLI port of Phase 20
|
|
3
|
+
* (docs/design/modules/20_模型量化系统.md).
|
|
4
|
+
*
|
|
5
|
+
* Desktop uses QuantizationManager (llama.cpp subprocess + AutoGPTQ),
|
|
6
|
+
* GGUFQuantizer, GPTQQuantizer with real progress tracking.
|
|
7
|
+
* CLI port ships:
|
|
8
|
+
*
|
|
9
|
+
* - Quantization job recording with status lifecycle
|
|
10
|
+
* - GGUF 14-level catalog + GPTQ bit-width catalog
|
|
11
|
+
* - Job CRUD (create/status/cancel/list/delete)
|
|
12
|
+
* - Simulated progress tracking (no real subprocess)
|
|
13
|
+
* - Stats aggregation
|
|
14
|
+
*
|
|
15
|
+
* What does NOT port: real llama-quantize subprocess execution,
|
|
16
|
+
* real AutoGPTQ Python subprocess, Ollama import (POST /api/create),
|
|
17
|
+
* real file-size tracking, stdout progress parsing.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import crypto from "crypto";
|
|
21
|
+
|
|
22
|
+
/* ── Constants ──────────────────────────────────────────── */
|
|
23
|
+
|
|
24
|
+
export const JOB_STATUS = Object.freeze({
|
|
25
|
+
PENDING: "pending",
|
|
26
|
+
RUNNING: "running",
|
|
27
|
+
COMPLETED: "completed",
|
|
28
|
+
FAILED: "failed",
|
|
29
|
+
CANCELLED: "cancelled",
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export const QUANT_TYPE = Object.freeze({
|
|
33
|
+
GGUF: "gguf",
|
|
34
|
+
GPTQ: "gptq",
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
export const GGUF_LEVELS = Object.freeze([
|
|
38
|
+
{ level: "Q2_K", bits: 2, description: "最小体积, 最低质量" },
|
|
39
|
+
{ level: "Q3_K_S", bits: 3, description: "极小, 低质量" },
|
|
40
|
+
{ level: "Q3_K_M", bits: 3, description: "小, 中等质量" },
|
|
41
|
+
{ level: "Q3_K_L", bits: 3, description: "小, 较高质量" },
|
|
42
|
+
{ level: "Q4_0", bits: 4, description: "旧版4-bit量化" },
|
|
43
|
+
{ level: "Q4_K_S", bits: 4, description: "小, 良好质量 (推荐最低)" },
|
|
44
|
+
{ level: "Q4_K_M", bits: 4, description: "中等, 体积质量平衡 (推荐)" },
|
|
45
|
+
{ level: "Q5_0", bits: 5, description: "旧版5-bit量化" },
|
|
46
|
+
{ level: "Q5_K_S", bits: 5, description: "小, 很好质量" },
|
|
47
|
+
{ level: "Q5_K_M", bits: 5, description: "中等, 优秀质量" },
|
|
48
|
+
{ level: "Q6_K", bits: 6, description: "大, 接近无损" },
|
|
49
|
+
{ level: "Q8_0", bits: 8, description: "极大, 几乎无损" },
|
|
50
|
+
{ level: "F16", bits: 16, description: "半精度浮点, 无量化损失" },
|
|
51
|
+
{ level: "F32", bits: 32, description: "全精度浮点, 最大体积" },
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
export const GPTQ_BITS = Object.freeze([2, 3, 4, 8]);
|
|
55
|
+
|
|
56
|
+
/* ── State ──────────────────────────────────────────────── */
|
|
57
|
+
|
|
58
|
+
let _jobs = new Map();
|
|
59
|
+
|
|
60
|
+
function _id() {
|
|
61
|
+
return crypto.randomUUID();
|
|
62
|
+
}
|
|
63
|
+
function _now() {
|
|
64
|
+
return Date.now();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function _strip(row) {
|
|
68
|
+
if (!row) return null;
|
|
69
|
+
const out = {};
|
|
70
|
+
for (const [k, v] of Object.entries(row)) {
|
|
71
|
+
if (k !== "_rowid_" && k !== "rowid") out[k] = v;
|
|
72
|
+
}
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* ── Schema ─────────────────────────────────────────────── */
|
|
77
|
+
|
|
78
|
+
export function ensureQuantizationTables(db) {
|
|
79
|
+
db.exec(`CREATE TABLE IF NOT EXISTS quantization_jobs (
|
|
80
|
+
id TEXT PRIMARY KEY,
|
|
81
|
+
input_path TEXT NOT NULL,
|
|
82
|
+
output_path TEXT,
|
|
83
|
+
quant_type TEXT NOT NULL,
|
|
84
|
+
quant_level TEXT,
|
|
85
|
+
status TEXT DEFAULT 'pending',
|
|
86
|
+
progress REAL DEFAULT 0.0,
|
|
87
|
+
file_size_bytes INTEGER DEFAULT 0,
|
|
88
|
+
error_message TEXT,
|
|
89
|
+
config TEXT,
|
|
90
|
+
started_at INTEGER,
|
|
91
|
+
completed_at INTEGER,
|
|
92
|
+
created_at INTEGER NOT NULL,
|
|
93
|
+
updated_at INTEGER NOT NULL
|
|
94
|
+
)`);
|
|
95
|
+
|
|
96
|
+
_loadAll(db);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function _loadAll(db) {
|
|
100
|
+
_jobs.clear();
|
|
101
|
+
try {
|
|
102
|
+
for (const row of db.prepare("SELECT * FROM quantization_jobs").all()) {
|
|
103
|
+
const r = _strip(row);
|
|
104
|
+
_jobs.set(r.id, r);
|
|
105
|
+
}
|
|
106
|
+
} catch (_e) {
|
|
107
|
+
/* table may not exist */
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* ── Validation helpers ─────────────────────────────────── */
|
|
112
|
+
|
|
113
|
+
const VALID_STATUSES = new Set(Object.values(JOB_STATUS));
|
|
114
|
+
const VALID_GGUF_LEVELS = new Set(GGUF_LEVELS.map((l) => l.level));
|
|
115
|
+
|
|
116
|
+
function _isValidGgufLevel(level) {
|
|
117
|
+
return VALID_GGUF_LEVELS.has(level);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function _isValidGptqBits(bits) {
|
|
121
|
+
return GPTQ_BITS.includes(Number(bits));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* ── Job CRUD ───────────────────────────────────────────── */
|
|
125
|
+
|
|
126
|
+
export function createJob(
|
|
127
|
+
db,
|
|
128
|
+
{ inputPath, outputPath, quantType, quantLevel, config } = {},
|
|
129
|
+
) {
|
|
130
|
+
if (!inputPath) return { created: false, reason: "missing_input_path" };
|
|
131
|
+
if (!quantType || !Object.values(QUANT_TYPE).includes(quantType))
|
|
132
|
+
return { created: false, reason: "invalid_quant_type" };
|
|
133
|
+
|
|
134
|
+
if (quantType === "gguf") {
|
|
135
|
+
if (!quantLevel) return { created: false, reason: "missing_quant_level" };
|
|
136
|
+
if (!_isValidGgufLevel(quantLevel))
|
|
137
|
+
return { created: false, reason: "invalid_gguf_level" };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (quantType === "gptq") {
|
|
141
|
+
const bits = config?.bits ?? 4;
|
|
142
|
+
if (!_isValidGptqBits(bits))
|
|
143
|
+
return { created: false, reason: "invalid_gptq_bits" };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const id = _id();
|
|
147
|
+
const now = _now();
|
|
148
|
+
const configJson = config
|
|
149
|
+
? typeof config === "string"
|
|
150
|
+
? config
|
|
151
|
+
: JSON.stringify(config)
|
|
152
|
+
: null;
|
|
153
|
+
|
|
154
|
+
const entry = {
|
|
155
|
+
id,
|
|
156
|
+
input_path: inputPath,
|
|
157
|
+
output_path: outputPath || null,
|
|
158
|
+
quant_type: quantType,
|
|
159
|
+
quant_level: quantLevel || null,
|
|
160
|
+
status: "pending",
|
|
161
|
+
progress: 0,
|
|
162
|
+
file_size_bytes: 0,
|
|
163
|
+
error_message: null,
|
|
164
|
+
config: configJson,
|
|
165
|
+
started_at: null,
|
|
166
|
+
completed_at: null,
|
|
167
|
+
created_at: now,
|
|
168
|
+
updated_at: now,
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
db.prepare(
|
|
172
|
+
`INSERT INTO quantization_jobs (id, input_path, output_path, quant_type, quant_level, status, progress, file_size_bytes, error_message, config, started_at, completed_at, created_at, updated_at)
|
|
173
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
174
|
+
).run(
|
|
175
|
+
id,
|
|
176
|
+
entry.input_path,
|
|
177
|
+
entry.output_path,
|
|
178
|
+
entry.quant_type,
|
|
179
|
+
entry.quant_level,
|
|
180
|
+
"pending",
|
|
181
|
+
0,
|
|
182
|
+
0,
|
|
183
|
+
null,
|
|
184
|
+
configJson,
|
|
185
|
+
null,
|
|
186
|
+
null,
|
|
187
|
+
now,
|
|
188
|
+
now,
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
_jobs.set(id, entry);
|
|
192
|
+
return { created: true, jobId: id };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function getJob(db, id) {
|
|
196
|
+
const j = _jobs.get(id);
|
|
197
|
+
return j ? { ...j } : null;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export function listJobs(db, { status, quantType, limit = 50 } = {}) {
|
|
201
|
+
let results = [..._jobs.values()];
|
|
202
|
+
if (status) results = results.filter((j) => j.status === status);
|
|
203
|
+
if (quantType) results = results.filter((j) => j.quant_type === quantType);
|
|
204
|
+
return results
|
|
205
|
+
.sort((a, b) => b.created_at - a.created_at)
|
|
206
|
+
.slice(0, limit)
|
|
207
|
+
.map((j) => ({ ...j }));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function startJob(db, id) {
|
|
211
|
+
const j = _jobs.get(id);
|
|
212
|
+
if (!j) return { started: false, reason: "not_found" };
|
|
213
|
+
if (j.status !== "pending") return { started: false, reason: "not_pending" };
|
|
214
|
+
|
|
215
|
+
const now = _now();
|
|
216
|
+
j.status = "running";
|
|
217
|
+
j.started_at = now;
|
|
218
|
+
j.updated_at = now;
|
|
219
|
+
|
|
220
|
+
db.prepare(
|
|
221
|
+
"UPDATE quantization_jobs SET status = 'running', started_at = ?, updated_at = ? WHERE id = ?",
|
|
222
|
+
).run(now, now, id);
|
|
223
|
+
|
|
224
|
+
return { started: true, jobId: id };
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export function updateProgress(db, id, progress) {
|
|
228
|
+
const j = _jobs.get(id);
|
|
229
|
+
if (!j) return { updated: false, reason: "not_found" };
|
|
230
|
+
if (j.status !== "running") return { updated: false, reason: "not_running" };
|
|
231
|
+
|
|
232
|
+
const clamped = Math.max(0, Math.min(100, Number(progress) || 0));
|
|
233
|
+
const now = _now();
|
|
234
|
+
j.progress = clamped;
|
|
235
|
+
j.updated_at = now;
|
|
236
|
+
|
|
237
|
+
db.prepare(
|
|
238
|
+
"UPDATE quantization_jobs SET progress = ?, updated_at = ? WHERE id = ?",
|
|
239
|
+
).run(clamped, now, id);
|
|
240
|
+
|
|
241
|
+
return { updated: true, progress: clamped };
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export function completeJob(db, id, { outputPath, fileSizeBytes } = {}) {
|
|
245
|
+
const j = _jobs.get(id);
|
|
246
|
+
if (!j) return { completed: false, reason: "not_found" };
|
|
247
|
+
if (j.status !== "running")
|
|
248
|
+
return { completed: false, reason: "not_running" };
|
|
249
|
+
|
|
250
|
+
const now = _now();
|
|
251
|
+
j.status = "completed";
|
|
252
|
+
j.progress = 100;
|
|
253
|
+
j.completed_at = now;
|
|
254
|
+
j.updated_at = now;
|
|
255
|
+
if (outputPath) j.output_path = outputPath;
|
|
256
|
+
if (fileSizeBytes != null) j.file_size_bytes = fileSizeBytes;
|
|
257
|
+
|
|
258
|
+
db.prepare(
|
|
259
|
+
"UPDATE quantization_jobs SET status = 'completed', progress = 100, output_path = ?, file_size_bytes = ?, completed_at = ?, updated_at = ? WHERE id = ?",
|
|
260
|
+
).run(j.output_path, j.file_size_bytes, now, now, id);
|
|
261
|
+
|
|
262
|
+
return { completed: true, jobId: id };
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export function failJob(db, id, errorMessage) {
|
|
266
|
+
const j = _jobs.get(id);
|
|
267
|
+
if (!j) return { failed: false, reason: "not_found" };
|
|
268
|
+
if (j.status !== "running" && j.status !== "pending")
|
|
269
|
+
return { failed: false, reason: "not_active" };
|
|
270
|
+
|
|
271
|
+
const now = _now();
|
|
272
|
+
j.status = "failed";
|
|
273
|
+
j.error_message = errorMessage || null;
|
|
274
|
+
j.updated_at = now;
|
|
275
|
+
if (!j.completed_at) j.completed_at = now;
|
|
276
|
+
|
|
277
|
+
db.prepare(
|
|
278
|
+
"UPDATE quantization_jobs SET status = 'failed', error_message = ?, completed_at = ?, updated_at = ? WHERE id = ?",
|
|
279
|
+
).run(j.error_message, j.completed_at, now, id);
|
|
280
|
+
|
|
281
|
+
return { failed: true, jobId: id };
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export function cancelJob(db, id) {
|
|
285
|
+
const j = _jobs.get(id);
|
|
286
|
+
if (!j) return { cancelled: false, reason: "not_found" };
|
|
287
|
+
if (j.status === "completed" || j.status === "cancelled")
|
|
288
|
+
return { cancelled: false, reason: "already_terminal" };
|
|
289
|
+
|
|
290
|
+
const now = _now();
|
|
291
|
+
j.status = "cancelled";
|
|
292
|
+
j.updated_at = now;
|
|
293
|
+
if (!j.completed_at) j.completed_at = now;
|
|
294
|
+
|
|
295
|
+
db.prepare(
|
|
296
|
+
"UPDATE quantization_jobs SET status = 'cancelled', completed_at = ?, updated_at = ? WHERE id = ?",
|
|
297
|
+
).run(j.completed_at, now, id);
|
|
298
|
+
|
|
299
|
+
return { cancelled: true, jobId: id };
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export function deleteJob(db, id) {
|
|
303
|
+
const j = _jobs.get(id);
|
|
304
|
+
if (!j) return { deleted: false, reason: "not_found" };
|
|
305
|
+
if (j.status === "running")
|
|
306
|
+
return { deleted: false, reason: "still_running" };
|
|
307
|
+
|
|
308
|
+
_jobs.delete(id);
|
|
309
|
+
db.prepare("DELETE FROM quantization_jobs WHERE id = ?").run(id);
|
|
310
|
+
|
|
311
|
+
return { deleted: true };
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/* ── Stats ──────────────────────────────────────────────── */
|
|
315
|
+
|
|
316
|
+
export function getQuantizationStats(db) {
|
|
317
|
+
const jobs = [..._jobs.values()];
|
|
318
|
+
|
|
319
|
+
const byStatus = {};
|
|
320
|
+
for (const s of Object.values(JOB_STATUS)) byStatus[s] = 0;
|
|
321
|
+
for (const j of jobs) byStatus[j.status] = (byStatus[j.status] || 0) + 1;
|
|
322
|
+
|
|
323
|
+
const byType = {};
|
|
324
|
+
for (const t of Object.values(QUANT_TYPE)) byType[t] = 0;
|
|
325
|
+
for (const j of jobs) byType[j.quant_type] = (byType[j.quant_type] || 0) + 1;
|
|
326
|
+
|
|
327
|
+
const byLevel = {};
|
|
328
|
+
for (const j of jobs) {
|
|
329
|
+
if (j.quant_level)
|
|
330
|
+
byLevel[j.quant_level] = (byLevel[j.quant_level] || 0) + 1;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const completed = jobs.filter((j) => j.status === "completed");
|
|
334
|
+
const totalSizeBytes = completed.reduce(
|
|
335
|
+
(s, j) => s + (j.file_size_bytes || 0),
|
|
336
|
+
0,
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
const durations = completed
|
|
340
|
+
.filter((j) => j.started_at && j.completed_at)
|
|
341
|
+
.map((j) => j.completed_at - j.started_at);
|
|
342
|
+
const avgDurationMs =
|
|
343
|
+
durations.length > 0
|
|
344
|
+
? Math.round(durations.reduce((s, d) => s + d, 0) / durations.length)
|
|
345
|
+
: 0;
|
|
346
|
+
|
|
347
|
+
return {
|
|
348
|
+
total: jobs.length,
|
|
349
|
+
byStatus,
|
|
350
|
+
byType,
|
|
351
|
+
byLevel,
|
|
352
|
+
completed: completed.length,
|
|
353
|
+
totalSizeBytes,
|
|
354
|
+
avgDurationMs,
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/* ── Reset (tests) ──────────────────────────────────────── */
|
|
359
|
+
|
|
360
|
+
export function _resetState() {
|
|
361
|
+
_jobs.clear();
|
|
362
|
+
}
|