openkbs 0.0.71 → 0.0.73

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openkbs",
3
- "version": "0.0.71",
3
+ "version": "0.0.73",
4
4
  "description": "OpenKBS - Command Line Interface",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -41,7 +41,8 @@
41
41
  "cli-spinner": "^0.2.10",
42
42
  "commander": "^12.1.0",
43
43
  "express": "^4.21.0",
44
- "fs-extra": "^11.2.0"
44
+ "fs-extra": "^11.2.0",
45
+ "jsonwebtoken": "^9.0.3"
45
46
  },
46
47
  "devDependencies": {
47
48
  "pkg": "^5.8.1"
package/src/actions.js CHANGED
@@ -4,6 +4,8 @@ const path = require('path');
4
4
  const express = require('express');
5
5
  const { exec, execSync } = require('child_process');
6
6
  const https = require('https');
7
+ const crypto = require('crypto');
8
+ const jwt = require('jsonwebtoken');
7
9
 
8
10
  const {
9
11
  fetchLocalKBData, fetchKBJWT, createAccountIdFromPublicKey, signPayload, getUserProfile, getKB,
@@ -17,6 +19,16 @@ const TEMPLATE_DIR = path.join(os.homedir(), '.openkbs', 'templates');
17
19
  const jwtPath = path.join(os.homedir(), '.openkbs', 'clientJWT');
18
20
  const generateTransactionId = () => `${+new Date()}-${Math.floor(100000 + Math.random() * 900000)}`;
19
21
 
22
+ // Service registry for OpenKBS AI services (image generation)
23
+ const SERVICES = {
24
+ // Short aliases (recommended)
25
+ "gpt-image": { accountId: "e69424d275873af94993240df041ed78", model: "gpt-image-1" },
26
+ "gemini-image": { accountId: "bc7ab06216fa2bf6db5d8e573d4d2415", model: "gemini-2.5-flash-image" },
27
+ // Full names
28
+ "gpt-image-1": { accountId: "e69424d275873af94993240df041ed78", model: "gpt-image-1" },
29
+ "gemini-2.5-flash-image": { accountId: "bc7ab06216fa2bf6db5d8e573d4d2415", model: "gemini-2.5-flash-image" }
30
+ };
31
+
20
32
  /**
21
33
  * Find settings from settings.json - checks current dir, then functions/ or site/ subdirs
22
34
  * Returns full settings object with kbId, region, etc.
@@ -90,6 +102,140 @@ function getMimeType(filePath) {
90
102
  return MIME_TYPES[ext] || 'application/octet-stream';
91
103
  }
92
104
 
105
+ /**
106
+ * Read JSON payload from --data option or stdin
107
+ */
108
+ async function getPayloadFromInput(dataOption) {
109
+ if (dataOption) {
110
+ return JSON.parse(dataOption);
111
+ }
112
+
113
+ // Read from stdin if not a TTY
114
+ if (!process.stdin.isTTY) {
115
+ const chunks = [];
116
+ for await (const chunk of process.stdin) {
117
+ chunks.push(chunk);
118
+ }
119
+ const input = Buffer.concat(chunks).toString('utf8').trim();
120
+ if (input) {
121
+ return JSON.parse(input);
122
+ }
123
+ }
124
+
125
+ throw new Error('No payload provided. Use --data or pipe JSON to stdin.');
126
+ }
127
+
128
+ /**
129
+ * Call OpenKBS AI services directly with transactionJWT
130
+ */
131
+ async function serviceAction(options) {
132
+ try {
133
+ // 1. Get and validate payload
134
+ let payload;
135
+ try {
136
+ payload = await getPayloadFromInput(options.data);
137
+ } catch (e) {
138
+ console.red(`Error parsing payload: ${e.message}`);
139
+ process.exit(1);
140
+ }
141
+
142
+ // 2. Validate model
143
+ const model = options.model;
144
+ if (!SERVICES[model]) {
145
+ console.red(`Unknown model: ${model}`);
146
+ console.log(`Available models: ${Object.keys(SERVICES).join(', ')}`);
147
+ process.exit(1);
148
+ }
149
+
150
+ // 3. Add model to payload if not present (use actual model name from registry)
151
+ if (!payload.model) {
152
+ payload.model = SERVICES[model].model;
153
+ }
154
+
155
+ // 4. Get user profile and generate transactionJWT
156
+ const userProfile = await getUserProfile();
157
+ const publicKey = userProfile.walletPublicKey;
158
+ const privateKey = userProfile.walletPrivateKey;
159
+ const accountId = createAccountIdFromPublicKey(publicKey);
160
+
161
+ if (!publicKey || !privateKey) {
162
+ console.red('Wallet keys not found. Please login first with: openkbs login');
163
+ process.exit(1);
164
+ }
165
+
166
+ const txPayload = {
167
+ operation: "transfer",
168
+ resourceId: "credits",
169
+ transactionId: generateTransactionId(),
170
+ fromAccountId: accountId,
171
+ fromAccountPublicKey: publicKey,
172
+ toAccountId: SERVICES[model].accountId,
173
+ message: "",
174
+ maxAmount: parseInt(options.maxAmount || '300000'),
175
+ iat: Math.floor(Date.now() / 1000)
176
+ };
177
+
178
+ // Create private key object for jwt.sign()
179
+ const privateKeyObj = crypto.createPrivateKey({
180
+ key: Buffer.from(privateKey, 'base64'),
181
+ format: 'der',
182
+ type: 'pkcs8'
183
+ });
184
+
185
+ const transactionJWT = jwt.sign(txPayload, privateKeyObj, {
186
+ algorithm: 'ES256',
187
+ expiresIn: 60
188
+ });
189
+
190
+ // 5. Make POST request to openai.openkbs.com
191
+ const response = await fetch('https://openai.openkbs.com', {
192
+ method: 'POST',
193
+ headers: {
194
+ 'Content-Type': 'application/json',
195
+ 'transaction-jwt': transactionJWT
196
+ },
197
+ body: JSON.stringify(payload)
198
+ });
199
+
200
+ const data = await response.json();
201
+
202
+ // 6. Handle errors
203
+ if (!response.ok) {
204
+ if (response.status === 498) {
205
+ console.red('Invalid service transaction');
206
+ } else if (response.status === 499) {
207
+ console.red('Insufficient credits. Check your balance at https://openkbs.com');
208
+ } else {
209
+ console.red(`Service error (${response.status}): ${JSON.stringify(data)}`);
210
+ }
211
+ process.exit(1);
212
+ }
213
+
214
+ // 7. Handle image output - save to file if -o specified
215
+ // Support both {data:[{b64_json}]} and [{b64_json}] formats
216
+ const imageData = data?.data?.[0]?.b64_json || data?.[0]?.b64_json;
217
+ if (options.output && imageData) {
218
+ const buffer = Buffer.from(imageData, 'base64');
219
+ const outputPath = path.resolve(options.output);
220
+
221
+ // Ensure directory exists
222
+ await fs.ensureDir(path.dirname(outputPath));
223
+ await fs.writeFile(outputPath, buffer);
224
+
225
+ console.green(`Image saved: ${outputPath}`);
226
+ console.log(`Size: ${(buffer.length / 1024).toFixed(1)} KB`);
227
+ return;
228
+ }
229
+
230
+ // 8. Output response as JSON (for non-image or no -o flag)
231
+ console.log(JSON.stringify(data, null, 2));
232
+
233
+ } catch (error) {
234
+ console.red(`Error: ${error.message}`);
235
+ process.exit(1);
236
+ }
237
+ }
238
+
93
239
  async function signAction(options) {
94
240
  try {
95
241
  const userProfile = await getUserProfile();
@@ -2491,6 +2637,7 @@ async function stackCreateAction(name) {
2491
2637
 
2492
2638
  module.exports = {
2493
2639
  signAction,
2640
+ serviceAction,
2494
2641
  loginAction,
2495
2642
  pullAction,
2496
2643
  pushAction,
package/src/index.js CHANGED
@@ -4,6 +4,7 @@ const packageJson = require('../package.json');
4
4
 
5
5
  const {
6
6
  signAction,
7
+ serviceAction,
7
8
  loginAction,
8
9
  pullAction,
9
10
  pushAction,
@@ -308,4 +309,43 @@ Examples:
308
309
  $ openkbs pulse disable Disable Pulse
309
310
  `);
310
311
 
312
+ program
313
+ .command('service')
314
+ .description('Generate images using OpenKBS AI services')
315
+ .requiredOption('-m, --model <model>', 'Model: gpt-image or gemini-image')
316
+ .option('-d, --data <json>', 'JSON payload (or pipe via stdin)')
317
+ .option('-o, --output <path>', 'Save image output to file (for image generation)')
318
+ .option('--max-amount <amount>', 'Max credits to authorize', '300000')
319
+ .action(serviceAction)
320
+ .addHelpText('after', `
321
+ Examples:
322
+ # Generate image with GPT
323
+ $ openkbs service -m gpt-image -d '{"action":"createImage","prompt":"a cat"}' -o cat.png
324
+
325
+ # Generate with Gemini
326
+ $ openkbs service -m gemini-image -d '{"action":"createImage","prompt":"logo"}' -o logo.png
327
+
328
+ # Edit image (provide reference URL)
329
+ $ openkbs service -m gpt-image -d '{"action":"createImage","prompt":"make it blue","imageUrls":["https://..."]}' -o edited.png
330
+
331
+ Available models:
332
+ gpt-image OpenAI GPT Image (gpt-image-1.5)
333
+ gemini-image Google Gemini Flash (gemini-2.5-flash-image)
334
+
335
+ Options for gpt-image:
336
+ prompt (required) Text description of the image
337
+ size "1024x1024", "1024x1536", "1536x1024", "auto" (default: "auto")
338
+ quality "low", "medium", "high", "auto" (default: "auto")
339
+ n Number of images (default: 1)
340
+ output_format "png", "jpg", "webp" (default: "png")
341
+ background "transparent", "opaque", "auto" (default: "auto")
342
+ output_compression 0-100 for jpg/webp (default: 100)
343
+ imageUrls Array of URLs for editing/reference
344
+
345
+ Options for gemini-image:
346
+ prompt (required) Text description of the image
347
+ aspect_ratio "1:1", "16:9", "9:16", "4:3", "3:4" (default: "1:1")
348
+ imageUrls Array of URLs for reference
349
+ `);
350
+
311
351
  program.parse(process.argv);
@@ -123,6 +123,43 @@ openkbs pulse status # WebSocket status
123
123
  openkbs site push # Deploy static site
124
124
  ```
125
125
 
126
+ ### Image Generation Service
127
+ Generate images directly from CLI using OpenKBS AI services:
128
+
129
+ ```bash
130
+ # Generate with GPT
131
+ openkbs service -m gpt-image -d '{"action":"createImage","prompt":"a logo"}' -o logo.png
132
+
133
+ # Generate with Gemini
134
+ openkbs service -m gemini-image -d '{"action":"createImage","prompt":"hero image"}' -o hero.png
135
+
136
+ # Edit existing image
137
+ openkbs service -m gpt-image -d '{"action":"createImage","prompt":"make it blue","imageUrls":["https://..."]}' -o edited.png
138
+ ```
139
+
140
+ **Available models:**
141
+ - `gpt-image` - OpenAI GPT Image (gpt-image-1.5)
142
+ - `gemini-image` - Google Gemini Flash (gemini-2.5-flash-image)
143
+
144
+ **Options for gpt-image:**
145
+ | Option | Values | Default |
146
+ |--------|--------|---------|
147
+ | prompt | (required) | - |
148
+ | size | "1024x1024", "1024x1536", "1536x1024", "auto" | "auto" |
149
+ | quality | "low", "medium", "high", "auto" | "auto" |
150
+ | n | Number of images | 1 |
151
+ | output_format | "png", "jpg", "webp" | "png" |
152
+ | background | "transparent", "opaque", "auto" | "auto" |
153
+ | output_compression | 0-100 | 100 |
154
+ | imageUrls | Array of URLs for editing | - |
155
+
156
+ **Options for gemini-image:**
157
+ | Option | Values | Default |
158
+ |--------|--------|---------|
159
+ | prompt | (required) | - |
160
+ | aspect_ratio | "1:1", "16:9", "9:16", "4:3", "3:4" | "1:1" |
161
+ | imageUrls | Array of URLs for reference | - |
162
+
126
163
  ## Backend Handler Pattern
127
164
 
128
165
  Commands are XML tags with JSON content that the LLM outputs:
package/version.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.0.71",
2
+ "version": "0.0.73",
3
3
  "releaseDate": "2026-01-07",
4
- "releaseNotes": "OpenKBS CLI version 0.0.71"
4
+ "releaseNotes": "OpenKBS CLI version 0.0.73"
5
5
  }