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,329 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cc nlprog` — CLI surface for Phase 28 Natural Language Programming.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Command } from "commander";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
INTENT,
|
|
9
|
+
TRANSLATION_STATUS,
|
|
10
|
+
STYLE_CATEGORY,
|
|
11
|
+
ensureNlProgrammingTables,
|
|
12
|
+
classifyIntent,
|
|
13
|
+
extractEntities,
|
|
14
|
+
detectTechStack,
|
|
15
|
+
scoreCompleteness,
|
|
16
|
+
translate,
|
|
17
|
+
getTranslation,
|
|
18
|
+
listTranslations,
|
|
19
|
+
updateTranslationStatus,
|
|
20
|
+
refineTranslation,
|
|
21
|
+
removeTranslation,
|
|
22
|
+
addConvention,
|
|
23
|
+
getConvention,
|
|
24
|
+
listConventions,
|
|
25
|
+
removeConvention,
|
|
26
|
+
getNlProgrammingStats,
|
|
27
|
+
} from "../lib/nl-programming.js";
|
|
28
|
+
|
|
29
|
+
function _dbFromCtx(cmd) {
|
|
30
|
+
const root = cmd?.parent?.parent ?? cmd?.parent;
|
|
31
|
+
return root?._db;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function registerNlProgCommand(program) {
|
|
35
|
+
const nlp = new Command("nlprog")
|
|
36
|
+
.description("Natural language programming system (Phase 28)")
|
|
37
|
+
.hook("preAction", (thisCmd) => {
|
|
38
|
+
const db = _dbFromCtx(thisCmd);
|
|
39
|
+
if (db) ensureNlProgrammingTables(db);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
/* ── Catalogs ────────────────────────────────────── */
|
|
43
|
+
|
|
44
|
+
nlp
|
|
45
|
+
.command("intents")
|
|
46
|
+
.description("List supported intent types")
|
|
47
|
+
.option("--json", "JSON output")
|
|
48
|
+
.action((opts) => {
|
|
49
|
+
const intents = Object.values(INTENT);
|
|
50
|
+
if (opts.json) return console.log(JSON.stringify(intents, null, 2));
|
|
51
|
+
for (const i of intents) console.log(` ${i}`);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
nlp
|
|
55
|
+
.command("statuses")
|
|
56
|
+
.description("List translation statuses")
|
|
57
|
+
.option("--json", "JSON output")
|
|
58
|
+
.action((opts) => {
|
|
59
|
+
const statuses = Object.values(TRANSLATION_STATUS);
|
|
60
|
+
if (opts.json) return console.log(JSON.stringify(statuses, null, 2));
|
|
61
|
+
for (const s of statuses) console.log(` ${s}`);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
nlp
|
|
65
|
+
.command("style-categories")
|
|
66
|
+
.description("List style analysis categories")
|
|
67
|
+
.option("--json", "JSON output")
|
|
68
|
+
.action((opts) => {
|
|
69
|
+
const cats = Object.values(STYLE_CATEGORY);
|
|
70
|
+
if (opts.json) return console.log(JSON.stringify(cats, null, 2));
|
|
71
|
+
for (const c of cats) console.log(` ${c}`);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
/* ── Analysis (stateless) ───────────────────────── */
|
|
75
|
+
|
|
76
|
+
nlp
|
|
77
|
+
.command("classify <text>")
|
|
78
|
+
.description("Classify intent of natural language input")
|
|
79
|
+
.option("--json", "JSON output")
|
|
80
|
+
.action((text, opts) => {
|
|
81
|
+
const result = classifyIntent(text);
|
|
82
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
83
|
+
console.log(`Intent: ${result.intent}`);
|
|
84
|
+
console.log(`Confidence: ${result.confidence}`);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
nlp
|
|
88
|
+
.command("extract <text>")
|
|
89
|
+
.description("Extract entities from natural language input")
|
|
90
|
+
.option("--json", "JSON output")
|
|
91
|
+
.action((text, opts) => {
|
|
92
|
+
const result = extractEntities(text);
|
|
93
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
94
|
+
if (result.count === 0) return console.log("No entities found.");
|
|
95
|
+
console.log(`Found ${result.count} entity(ies):`);
|
|
96
|
+
for (const e of result.entities) {
|
|
97
|
+
console.log(` [${e.type}] ${e.value}`);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
nlp
|
|
102
|
+
.command("detect-stack <text>")
|
|
103
|
+
.description("Detect technology stack from text")
|
|
104
|
+
.option("--json", "JSON output")
|
|
105
|
+
.action((text, opts) => {
|
|
106
|
+
const result = detectTechStack(text);
|
|
107
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
108
|
+
if (result.detected.length === 0)
|
|
109
|
+
return console.log("No tech stack detected.");
|
|
110
|
+
console.log(`Primary: ${result.primary}`);
|
|
111
|
+
console.log(`All: ${result.detected.join(", ")}`);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
/* ── Translation ────────────────────────────────── */
|
|
115
|
+
|
|
116
|
+
nlp
|
|
117
|
+
.command("translate <text>")
|
|
118
|
+
.description("Translate natural language to spec (heuristic)")
|
|
119
|
+
.option("-i, --intent <intent>", "Override intent classification")
|
|
120
|
+
.option("-s, --spec <json>", "Attach spec JSON")
|
|
121
|
+
.option("-a, --ambiguities <json>", "Ambiguity list JSON")
|
|
122
|
+
.option("--json", "JSON output")
|
|
123
|
+
.action((text, opts) => {
|
|
124
|
+
const db = _dbFromCtx(nlp);
|
|
125
|
+
const result = translate(db, {
|
|
126
|
+
text,
|
|
127
|
+
intent: opts.intent,
|
|
128
|
+
spec: opts.spec,
|
|
129
|
+
ambiguities: opts.ambiguities,
|
|
130
|
+
});
|
|
131
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
132
|
+
if (result.translated) {
|
|
133
|
+
console.log(`Translation: ${result.translationId}`);
|
|
134
|
+
console.log(`Intent: ${result.intent}`);
|
|
135
|
+
console.log(`Completeness: ${result.completeness}`);
|
|
136
|
+
} else console.log(`Failed: ${result.reason}`);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
nlp
|
|
140
|
+
.command("show <id>")
|
|
141
|
+
.description("Show translation details")
|
|
142
|
+
.option("--json", "JSON output")
|
|
143
|
+
.action((id, opts) => {
|
|
144
|
+
const db = _dbFromCtx(nlp);
|
|
145
|
+
const t = getTranslation(db, id);
|
|
146
|
+
if (!t) return console.log("Translation not found.");
|
|
147
|
+
if (opts.json) return console.log(JSON.stringify(t, null, 2));
|
|
148
|
+
console.log(`ID: ${t.id}`);
|
|
149
|
+
console.log(`Input: ${t.input_text.slice(0, 80)}`);
|
|
150
|
+
console.log(`Intent: ${t.intent}`);
|
|
151
|
+
console.log(`Status: ${t.status}`);
|
|
152
|
+
console.log(`Completeness: ${t.completeness_score}`);
|
|
153
|
+
if (t.entities) console.log(`Entities: ${t.entities.slice(0, 60)}`);
|
|
154
|
+
if (t.tech_stack) console.log(`Tech Stack: ${t.tech_stack}`);
|
|
155
|
+
if (t.ambiguities)
|
|
156
|
+
console.log(`Ambiguities: ${t.ambiguities.slice(0, 60)}`);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
nlp
|
|
160
|
+
.command("list")
|
|
161
|
+
.description("List translations")
|
|
162
|
+
.option("-i, --intent <intent>", "Filter by intent")
|
|
163
|
+
.option("-s, --status <status>", "Filter by status")
|
|
164
|
+
.option("--limit <n>", "Max results", parseInt)
|
|
165
|
+
.option("--json", "JSON output")
|
|
166
|
+
.action((opts) => {
|
|
167
|
+
const db = _dbFromCtx(nlp);
|
|
168
|
+
const results = listTranslations(db, {
|
|
169
|
+
intent: opts.intent,
|
|
170
|
+
status: opts.status,
|
|
171
|
+
limit: opts.limit,
|
|
172
|
+
});
|
|
173
|
+
if (opts.json) return console.log(JSON.stringify(results, null, 2));
|
|
174
|
+
if (results.length === 0) return console.log("No translations.");
|
|
175
|
+
for (const t of results) {
|
|
176
|
+
console.log(
|
|
177
|
+
` ${t.intent.padEnd(18)} ${t.status.padEnd(10)} comp:${String(t.completeness_score).padEnd(6)} ${t.input_text.slice(0, 40).padEnd(42)} ${t.id.slice(0, 8)}`,
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
nlp
|
|
183
|
+
.command("status <id> <status>")
|
|
184
|
+
.description("Update translation status (draft/complete/refined)")
|
|
185
|
+
.option("--json", "JSON output")
|
|
186
|
+
.action((id, status, opts) => {
|
|
187
|
+
const db = _dbFromCtx(nlp);
|
|
188
|
+
const result = updateTranslationStatus(db, id, status);
|
|
189
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
190
|
+
console.log(
|
|
191
|
+
result.updated
|
|
192
|
+
? `Status updated to: ${result.status}`
|
|
193
|
+
: `Failed: ${result.reason}`,
|
|
194
|
+
);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
nlp
|
|
198
|
+
.command("refine <id>")
|
|
199
|
+
.description("Refine a translation with updated spec")
|
|
200
|
+
.option("-s, --spec <json>", "Updated spec JSON")
|
|
201
|
+
.option("-a, --ambiguities <json>", "Updated ambiguities JSON")
|
|
202
|
+
.option("--json", "JSON output")
|
|
203
|
+
.action((id, opts) => {
|
|
204
|
+
const db = _dbFromCtx(nlp);
|
|
205
|
+
const result = refineTranslation(db, id, {
|
|
206
|
+
spec: opts.spec,
|
|
207
|
+
ambiguities: opts.ambiguities,
|
|
208
|
+
});
|
|
209
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
210
|
+
if (result.refined)
|
|
211
|
+
console.log(`Refined (completeness: ${result.completeness})`);
|
|
212
|
+
else console.log(`Failed: ${result.reason}`);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
nlp
|
|
216
|
+
.command("remove <id>")
|
|
217
|
+
.description("Remove a translation")
|
|
218
|
+
.option("--json", "JSON output")
|
|
219
|
+
.action((id, opts) => {
|
|
220
|
+
const db = _dbFromCtx(nlp);
|
|
221
|
+
const result = removeTranslation(db, id);
|
|
222
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
223
|
+
console.log(
|
|
224
|
+
result.removed ? "Translation removed." : `Failed: ${result.reason}`,
|
|
225
|
+
);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
/* ── Conventions ────────────────────────────────── */
|
|
229
|
+
|
|
230
|
+
nlp
|
|
231
|
+
.command("convention-add")
|
|
232
|
+
.description("Add a project convention")
|
|
233
|
+
.requiredOption(
|
|
234
|
+
"-c, --category <cat>",
|
|
235
|
+
"Category (naming/architecture/testing/style/imports/components)",
|
|
236
|
+
)
|
|
237
|
+
.requiredOption("-p, --pattern <text>", "Pattern description")
|
|
238
|
+
.option("-e, --examples <json>", "Examples JSON")
|
|
239
|
+
.option("-f, --confidence <n>", "Confidence (0-1)", parseFloat)
|
|
240
|
+
.option("-s, --source-files <json>", "Source files JSON")
|
|
241
|
+
.option("--json", "JSON output")
|
|
242
|
+
.action((opts) => {
|
|
243
|
+
const db = _dbFromCtx(nlp);
|
|
244
|
+
const result = addConvention(db, {
|
|
245
|
+
category: opts.category,
|
|
246
|
+
pattern: opts.pattern,
|
|
247
|
+
examples: opts.examples,
|
|
248
|
+
confidence: opts.confidence,
|
|
249
|
+
sourceFiles: opts.sourceFiles,
|
|
250
|
+
});
|
|
251
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
252
|
+
if (result.added) console.log(`Convention added: ${result.conventionId}`);
|
|
253
|
+
else console.log(`Failed: ${result.reason}`);
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
nlp
|
|
257
|
+
.command("convention-show <id>")
|
|
258
|
+
.description("Show convention details")
|
|
259
|
+
.option("--json", "JSON output")
|
|
260
|
+
.action((id, opts) => {
|
|
261
|
+
const db = _dbFromCtx(nlp);
|
|
262
|
+
const c = getConvention(db, id);
|
|
263
|
+
if (!c) return console.log("Convention not found.");
|
|
264
|
+
if (opts.json) return console.log(JSON.stringify(c, null, 2));
|
|
265
|
+
console.log(`ID: ${c.id}`);
|
|
266
|
+
console.log(`Category: ${c.category}`);
|
|
267
|
+
console.log(`Pattern: ${c.pattern}`);
|
|
268
|
+
console.log(`Confidence: ${c.confidence}`);
|
|
269
|
+
if (c.examples) console.log(`Examples: ${c.examples.slice(0, 60)}`);
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
nlp
|
|
273
|
+
.command("conventions")
|
|
274
|
+
.description("List project conventions")
|
|
275
|
+
.option("-c, --category <cat>", "Filter by category")
|
|
276
|
+
.option("--limit <n>", "Max results", parseInt)
|
|
277
|
+
.option("--json", "JSON output")
|
|
278
|
+
.action((opts) => {
|
|
279
|
+
const db = _dbFromCtx(nlp);
|
|
280
|
+
const results = listConventions(db, {
|
|
281
|
+
category: opts.category,
|
|
282
|
+
limit: opts.limit,
|
|
283
|
+
});
|
|
284
|
+
if (opts.json) return console.log(JSON.stringify(results, null, 2));
|
|
285
|
+
if (results.length === 0) return console.log("No conventions.");
|
|
286
|
+
for (const c of results) {
|
|
287
|
+
console.log(
|
|
288
|
+
` ${c.category.padEnd(14)} conf:${String(c.confidence).padEnd(5)} ${c.pattern.slice(0, 40).padEnd(42)} ${c.id.slice(0, 8)}`,
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
nlp
|
|
294
|
+
.command("convention-remove <id>")
|
|
295
|
+
.description("Remove a convention")
|
|
296
|
+
.option("--json", "JSON output")
|
|
297
|
+
.action((id, opts) => {
|
|
298
|
+
const db = _dbFromCtx(nlp);
|
|
299
|
+
const result = removeConvention(db, id);
|
|
300
|
+
if (opts.json) return console.log(JSON.stringify(result, null, 2));
|
|
301
|
+
console.log(
|
|
302
|
+
result.removed ? "Convention removed." : `Failed: ${result.reason}`,
|
|
303
|
+
);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
/* ── Stats ──────────────────────────────────────── */
|
|
307
|
+
|
|
308
|
+
nlp
|
|
309
|
+
.command("stats")
|
|
310
|
+
.description("NL Programming statistics")
|
|
311
|
+
.option("--json", "JSON output")
|
|
312
|
+
.action((opts) => {
|
|
313
|
+
const db = _dbFromCtx(nlp);
|
|
314
|
+
const s = getNlProgrammingStats(db);
|
|
315
|
+
if (opts.json) return console.log(JSON.stringify(s, null, 2));
|
|
316
|
+
console.log(
|
|
317
|
+
`Translations: ${s.translations.total} (avg completeness: ${s.translations.avgCompleteness})`,
|
|
318
|
+
);
|
|
319
|
+
for (const [intent, count] of Object.entries(s.translations.byIntent)) {
|
|
320
|
+
if (count > 0) console.log(` ${intent.padEnd(18)} ${count}`);
|
|
321
|
+
}
|
|
322
|
+
console.log(`Conventions: ${s.conventions.total}`);
|
|
323
|
+
for (const [cat, count] of Object.entries(s.conventions.byCategory)) {
|
|
324
|
+
if (count > 0) console.log(` ${cat.padEnd(14)} ${count}`);
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
program.addCommand(nlp);
|
|
329
|
+
}
|
package/src/commands/nostr.js
CHANGED
|
@@ -14,6 +14,10 @@ import {
|
|
|
14
14
|
getEvents,
|
|
15
15
|
generateKeypair,
|
|
16
16
|
mapDid,
|
|
17
|
+
publishDirectMessage,
|
|
18
|
+
decryptDirectMessage,
|
|
19
|
+
publishDeletion,
|
|
20
|
+
publishReaction,
|
|
17
21
|
} from "../lib/nostr-bridge.js";
|
|
18
22
|
|
|
19
23
|
export function registerNostrCommand(program) {
|
|
@@ -80,9 +84,13 @@ export function registerNostrCommand(program) {
|
|
|
80
84
|
|
|
81
85
|
nostr
|
|
82
86
|
.command("publish <content>")
|
|
83
|
-
.description("Publish a text note event")
|
|
87
|
+
.description("Publish a text note event (signed if --privkey provided)")
|
|
84
88
|
.option("-k, --kind <n>", "Event kind", "1")
|
|
85
|
-
.option("-p, --pubkey <key>", "Author public key")
|
|
89
|
+
.option("-p, --pubkey <key>", "Author public key (unsigned path)")
|
|
90
|
+
.option(
|
|
91
|
+
"--privkey <hex>",
|
|
92
|
+
"Sign event with this 32-byte private key (hex). Pubkey is derived.",
|
|
93
|
+
)
|
|
86
94
|
.action(async (content, options) => {
|
|
87
95
|
try {
|
|
88
96
|
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
@@ -98,12 +106,17 @@ export function registerNostrCommand(program) {
|
|
|
98
106
|
parseInt(options.kind),
|
|
99
107
|
content,
|
|
100
108
|
options.pubkey,
|
|
109
|
+
[],
|
|
110
|
+
options.privkey,
|
|
101
111
|
);
|
|
102
112
|
logger.success("Event published");
|
|
103
113
|
logger.log(
|
|
104
|
-
` ${chalk.bold("ID:")}
|
|
114
|
+
` ${chalk.bold("ID:")} ${chalk.cyan(result.event.id.slice(0, 16))}...`,
|
|
115
|
+
);
|
|
116
|
+
logger.log(
|
|
117
|
+
` ${chalk.bold("Signed:")} ${result.event.sig ? chalk.green("yes (BIP-340)") : chalk.yellow("no — will be rejected by real relays")}`,
|
|
105
118
|
);
|
|
106
|
-
logger.log(` ${chalk.bold("Sent:")}
|
|
119
|
+
logger.log(` ${chalk.bold("Sent:")} ${result.sentCount} relay(s)`);
|
|
107
120
|
await shutdown();
|
|
108
121
|
} catch (err) {
|
|
109
122
|
logger.error(`Failed: ${err.message}`);
|
|
@@ -158,11 +171,12 @@ export function registerNostrCommand(program) {
|
|
|
158
171
|
if (options.json) {
|
|
159
172
|
console.log(JSON.stringify(kp, null, 2));
|
|
160
173
|
} else {
|
|
161
|
-
logger.success("Keypair generated");
|
|
162
|
-
logger.log(` ${chalk.bold("
|
|
174
|
+
logger.success("Keypair generated (BIP-340 schnorr / NIP-19)");
|
|
175
|
+
logger.log(` ${chalk.bold("npub:")} ${chalk.cyan(kp.npub)}`);
|
|
163
176
|
logger.log(
|
|
164
|
-
` ${chalk.bold("
|
|
177
|
+
` ${chalk.bold("nsec:")} ${chalk.yellow(kp.nsec.slice(0, 20))}… ${chalk.dim("(keep private!)")}`,
|
|
165
178
|
);
|
|
179
|
+
logger.log(` ${chalk.bold("pubHex:")} ${kp.publicKey}`);
|
|
166
180
|
}
|
|
167
181
|
} catch (err) {
|
|
168
182
|
logger.error(`Failed: ${err.message}`);
|
|
@@ -182,4 +196,179 @@ export function registerNostrCommand(program) {
|
|
|
182
196
|
process.exit(1);
|
|
183
197
|
}
|
|
184
198
|
});
|
|
199
|
+
|
|
200
|
+
// ── NIP-04: Encrypted Direct Message ──────────────────────────────
|
|
201
|
+
|
|
202
|
+
nostr
|
|
203
|
+
.command("dm <recipientPubkey> <plaintext>")
|
|
204
|
+
.description("Send a NIP-04 encrypted direct message (kind=4)")
|
|
205
|
+
.requiredOption("--sender-priv <hex>", "Sender's 32-byte private key (hex)")
|
|
206
|
+
.requiredOption(
|
|
207
|
+
"--sender-pub <hex>",
|
|
208
|
+
"Sender's 32-byte x-only public key (hex)",
|
|
209
|
+
)
|
|
210
|
+
.option("--json", "Output as JSON")
|
|
211
|
+
.action(async (recipientPubkey, plaintext, options) => {
|
|
212
|
+
try {
|
|
213
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
214
|
+
if (!ctx.db) {
|
|
215
|
+
logger.error("Database not available");
|
|
216
|
+
process.exit(1);
|
|
217
|
+
}
|
|
218
|
+
const db = ctx.db.getDatabase();
|
|
219
|
+
ensureNostrTables(db);
|
|
220
|
+
|
|
221
|
+
const result = publishDirectMessage(db, {
|
|
222
|
+
senderPrivkey: options.senderPriv,
|
|
223
|
+
senderPubkey: options.senderPub,
|
|
224
|
+
recipientPubkey,
|
|
225
|
+
plaintext,
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
if (options.json) {
|
|
229
|
+
console.log(JSON.stringify(result, null, 2));
|
|
230
|
+
} else {
|
|
231
|
+
logger.success("Encrypted DM sent");
|
|
232
|
+
logger.log(
|
|
233
|
+
` ${chalk.bold("ID:")} ${chalk.cyan(result.event.id.slice(0, 16))}...`,
|
|
234
|
+
);
|
|
235
|
+
logger.log(` ${chalk.bold("Sent:")} ${result.sentCount} relay(s)`);
|
|
236
|
+
}
|
|
237
|
+
await shutdown();
|
|
238
|
+
} catch (err) {
|
|
239
|
+
logger.error(`Failed: ${err.message}`);
|
|
240
|
+
process.exit(1);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
nostr
|
|
245
|
+
.command("dm-decrypt <eventId>")
|
|
246
|
+
.description("Decrypt a stored NIP-04 direct message by event id")
|
|
247
|
+
.requiredOption(
|
|
248
|
+
"--recipient-priv <hex>",
|
|
249
|
+
"Recipient's 32-byte private key (hex)",
|
|
250
|
+
)
|
|
251
|
+
.option("--json", "Output as JSON")
|
|
252
|
+
.action(async (eventId, options) => {
|
|
253
|
+
try {
|
|
254
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
255
|
+
if (!ctx.db) {
|
|
256
|
+
logger.error("Database not available");
|
|
257
|
+
process.exit(1);
|
|
258
|
+
}
|
|
259
|
+
const db = ctx.db.getDatabase();
|
|
260
|
+
ensureNostrTables(db);
|
|
261
|
+
|
|
262
|
+
const events = getEvents({ kinds: [4], limit: 1000 });
|
|
263
|
+
const event = events.find((e) => e.id === eventId);
|
|
264
|
+
if (!event) {
|
|
265
|
+
logger.error(`Event not found: ${eventId}`);
|
|
266
|
+
process.exit(1);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const plaintext = decryptDirectMessage({
|
|
270
|
+
event,
|
|
271
|
+
recipientPrivkey: options.recipientPriv,
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
if (options.json) {
|
|
275
|
+
console.log(JSON.stringify({ success: true, plaintext }, null, 2));
|
|
276
|
+
} else {
|
|
277
|
+
logger.success("Decrypted");
|
|
278
|
+
logger.log(
|
|
279
|
+
` ${chalk.bold("From:")} ${chalk.cyan(event.pubkey.slice(0, 16))}...`,
|
|
280
|
+
);
|
|
281
|
+
logger.log(` ${chalk.bold("Message:")} ${plaintext}`);
|
|
282
|
+
}
|
|
283
|
+
await shutdown();
|
|
284
|
+
} catch (err) {
|
|
285
|
+
logger.error(`Failed: ${err.message}`);
|
|
286
|
+
process.exit(1);
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// ── NIP-09: Event Deletion Request ─────────────────────────────────
|
|
291
|
+
|
|
292
|
+
nostr
|
|
293
|
+
.command("delete <eventIds...>")
|
|
294
|
+
.description("Publish a NIP-09 deletion request (kind=5)")
|
|
295
|
+
.option("-r, --reason <text>", "Reason for deletion", "")
|
|
296
|
+
.option("-p, --pubkey <key>", "Author public key")
|
|
297
|
+
.option("--json", "Output as JSON")
|
|
298
|
+
.action(async (eventIds, options) => {
|
|
299
|
+
try {
|
|
300
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
301
|
+
if (!ctx.db) {
|
|
302
|
+
logger.error("Database not available");
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
305
|
+
const db = ctx.db.getDatabase();
|
|
306
|
+
ensureNostrTables(db);
|
|
307
|
+
|
|
308
|
+
const result = publishDeletion(db, {
|
|
309
|
+
eventIds,
|
|
310
|
+
reason: options.reason,
|
|
311
|
+
pubkey: options.pubkey,
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
if (options.json) {
|
|
315
|
+
console.log(JSON.stringify(result, null, 2));
|
|
316
|
+
} else {
|
|
317
|
+
logger.success(
|
|
318
|
+
`Deletion request published for ${eventIds.length} event(s)`,
|
|
319
|
+
);
|
|
320
|
+
logger.log(
|
|
321
|
+
` ${chalk.bold("ID:")} ${chalk.cyan(result.event.id.slice(0, 16))}...`,
|
|
322
|
+
);
|
|
323
|
+
logger.log(` ${chalk.bold("Sent:")} ${result.sentCount} relay(s)`);
|
|
324
|
+
}
|
|
325
|
+
await shutdown();
|
|
326
|
+
} catch (err) {
|
|
327
|
+
logger.error(`Failed: ${err.message}`);
|
|
328
|
+
process.exit(1);
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
// ── NIP-25: Reactions ──────────────────────────────────────────────
|
|
333
|
+
|
|
334
|
+
nostr
|
|
335
|
+
.command("react <targetEventId> <targetPubkey>")
|
|
336
|
+
.description(
|
|
337
|
+
'Publish a NIP-25 reaction (kind=7). content "+" | "-" | emoji',
|
|
338
|
+
)
|
|
339
|
+
.option("-c, --content <symbol>", "Reaction symbol", "+")
|
|
340
|
+
.option("-p, --pubkey <key>", "Author public key")
|
|
341
|
+
.option("--json", "Output as JSON")
|
|
342
|
+
.action(async (targetEventId, targetPubkey, options) => {
|
|
343
|
+
try {
|
|
344
|
+
const ctx = await bootstrap({ verbose: program.opts().verbose });
|
|
345
|
+
if (!ctx.db) {
|
|
346
|
+
logger.error("Database not available");
|
|
347
|
+
process.exit(1);
|
|
348
|
+
}
|
|
349
|
+
const db = ctx.db.getDatabase();
|
|
350
|
+
ensureNostrTables(db);
|
|
351
|
+
|
|
352
|
+
const result = publishReaction(db, {
|
|
353
|
+
targetEventId,
|
|
354
|
+
targetPubkey,
|
|
355
|
+
content: options.content,
|
|
356
|
+
pubkey: options.pubkey,
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
if (options.json) {
|
|
360
|
+
console.log(JSON.stringify(result, null, 2));
|
|
361
|
+
} else {
|
|
362
|
+
logger.success(`Reaction "${options.content}" published`);
|
|
363
|
+
logger.log(
|
|
364
|
+
` ${chalk.bold("ID:")} ${chalk.cyan(result.event.id.slice(0, 16))}...`,
|
|
365
|
+
);
|
|
366
|
+
logger.log(` ${chalk.bold("Sent:")} ${result.sentCount} relay(s)`);
|
|
367
|
+
}
|
|
368
|
+
await shutdown();
|
|
369
|
+
} catch (err) {
|
|
370
|
+
logger.error(`Failed: ${err.message}`);
|
|
371
|
+
process.exit(1);
|
|
372
|
+
}
|
|
373
|
+
});
|
|
185
374
|
}
|