@harpiaresearch/vref 1.0.1 → 1.0.2
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/LICENSE +1 -1
- package/README.md +41 -13
- package/dist/VREFReader.d.ts +4 -0
- package/dist/VREFReader.js +19 -0
- package/dist/VREFWriter.d.ts +1 -1
- package/dist/VREFWriter.js +67 -13
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +153 -30
- package/dist/types.d.ts +6 -2
- package/package.json +4 -4
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -146,14 +146,16 @@ npx @harpiaresearch/vref
|
|
|
146
146
|
|
|
147
147
|
**CLI:**
|
|
148
148
|
```bash
|
|
149
|
-
# From a directory
|
|
149
|
+
# From a directory (via npx or global/local vref)
|
|
150
150
|
npx @harpiaresearch/vref ./my-images -o references.vref
|
|
151
151
|
|
|
152
|
-
# With metadata
|
|
152
|
+
# With metadata (including title name)
|
|
153
153
|
npx @harpiaresearch/vref ./images -o pack.vref \
|
|
154
154
|
-n "My Reference Pack" \
|
|
155
155
|
-d "Collection of art references" \
|
|
156
|
-
-t "art,style,inspiration"
|
|
156
|
+
-t "art,style,inspiration" \
|
|
157
|
+
-a "Your Name" \
|
|
158
|
+
-l "CC-BY-4.0"
|
|
157
159
|
```
|
|
158
160
|
|
|
159
161
|
**Code:**
|
|
@@ -161,22 +163,40 @@ npx @harpiaresearch/vref ./images -o pack.vref \
|
|
|
161
163
|
import { VREFWriter } from '@harpiaresearch/vref';
|
|
162
164
|
|
|
163
165
|
const writer = new VREFWriter({
|
|
164
|
-
|
|
165
|
-
description: '
|
|
166
|
+
name: 'Art Style References',
|
|
167
|
+
description: 'Collection of curated art style references',
|
|
166
168
|
tags: ['art', 'style'],
|
|
169
|
+
author: 'Your Name',
|
|
170
|
+
license: 'CC-BY-4.0',
|
|
167
171
|
});
|
|
168
172
|
|
|
169
173
|
writer.addImagesFromDirectory('./images');
|
|
170
174
|
writer.write('references.vref');
|
|
171
175
|
```
|
|
172
176
|
|
|
177
|
+
### Inspecting, Validating & Extracting via CLI
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
# Inspect metadata and images in a pack
|
|
181
|
+
vref info references.vref
|
|
182
|
+
|
|
183
|
+
# Validate format and manifest integrity
|
|
184
|
+
vref validate references.vref
|
|
185
|
+
|
|
186
|
+
# Extract images to a directory
|
|
187
|
+
vref extract references.vref ./extracted-images
|
|
188
|
+
```
|
|
189
|
+
|
|
173
190
|
### Reading a .vref File
|
|
174
191
|
|
|
175
192
|
```typescript
|
|
176
193
|
import { VREFReader } from '@harpiaresearch/vref';
|
|
177
194
|
|
|
178
|
-
// Read file
|
|
179
|
-
const vref = VREFReader.read('references.vref', {
|
|
195
|
+
// Read file (optional validation & preloading)
|
|
196
|
+
const vref = VREFReader.read('references.vref', {
|
|
197
|
+
validate: true,
|
|
198
|
+
loadImages: true,
|
|
199
|
+
});
|
|
180
200
|
|
|
181
201
|
console.log(`Loaded ${vref.manifest.imageCount} images`);
|
|
182
202
|
|
|
@@ -185,6 +205,9 @@ const randomSamples = vref.sample(3);
|
|
|
185
205
|
|
|
186
206
|
// Get specific image
|
|
187
207
|
const image = vref.getImage('photo1.png');
|
|
208
|
+
|
|
209
|
+
// Extract all images to disk
|
|
210
|
+
VREFReader.extract('references.vref', './extracted');
|
|
188
211
|
```
|
|
189
212
|
|
|
190
213
|
---
|
|
@@ -243,7 +266,7 @@ references.vref
|
|
|
243
266
|
|
|
244
267
|
```json
|
|
245
268
|
{
|
|
246
|
-
"version": "1.0.
|
|
269
|
+
"version": "1.0.2",
|
|
247
270
|
"format": "VREF",
|
|
248
271
|
"fileName": "references.vref",
|
|
249
272
|
"imageCount": 24,
|
|
@@ -256,8 +279,9 @@ references.vref
|
|
|
256
279
|
"height": 1080
|
|
257
280
|
}
|
|
258
281
|
],
|
|
259
|
-
"createdAt": "
|
|
282
|
+
"createdAt": "2026-10-13T10:30:00.000Z",
|
|
260
283
|
"metadata": {
|
|
284
|
+
"name": "RPG Sprites",
|
|
261
285
|
"description": "Collection of references",
|
|
262
286
|
"tags": ["style", "mood"],
|
|
263
287
|
"author": "Your Name",
|
|
@@ -286,8 +310,9 @@ No company owns it. Community-driven. Free forever.
|
|
|
286
310
|
### 📦 Already Shipping
|
|
287
311
|
- ✅ npm package published
|
|
288
312
|
- ✅ Full TypeScript support
|
|
289
|
-
- ✅ CLI tool ready
|
|
290
|
-
- ✅
|
|
313
|
+
- ✅ CLI tool ready (`create`, `info`, `validate`, `extract`)
|
|
314
|
+
- ✅ Automated test suite (`node:test`)
|
|
315
|
+
- ✅ Complete documentation
|
|
291
316
|
|
|
292
317
|
### 🇧🇷 Made in Brazil
|
|
293
318
|
Harpia AI Research is putting Brazil on the map of AI innovation.
|
|
@@ -306,6 +331,7 @@ class VREFWriter {
|
|
|
306
331
|
|
|
307
332
|
write(outputPath: string): void;
|
|
308
333
|
getImageCount(): number;
|
|
334
|
+
clear(): void;
|
|
309
335
|
}
|
|
310
336
|
```
|
|
311
337
|
|
|
@@ -316,6 +342,7 @@ class VREFReader {
|
|
|
316
342
|
static read(filePath: string, options?: VREFReadOptions): VREFReadResult;
|
|
317
343
|
static readManifest(filePath: string): VREFManifest;
|
|
318
344
|
static validate(filePath: string): { valid: boolean; errors: string[] };
|
|
345
|
+
static extract(filePath: string, targetDir: string): void;
|
|
319
346
|
}
|
|
320
347
|
```
|
|
321
348
|
|
|
@@ -338,7 +365,8 @@ Full API documentation: [TypeScript definitions](src/types.ts)
|
|
|
338
365
|
|
|
339
366
|
### Phase 1 ✅ (Done)
|
|
340
367
|
- Core library implementation
|
|
341
|
-
- CLI tool
|
|
368
|
+
- CLI tool (`create`, `info`, `validate`, `extract`)
|
|
369
|
+
- Automated test coverage
|
|
342
370
|
- npm package published
|
|
343
371
|
- Full documentation
|
|
344
372
|
|
|
@@ -379,7 +407,7 @@ VREF is just getting started. We need:
|
|
|
379
407
|
|
|
380
408
|
This project is licensed under the **BSD 3-Clause License** - see the [LICENSE](LICENSE) file for details.
|
|
381
409
|
|
|
382
|
-
Copyright (c)
|
|
410
|
+
Copyright (c) 2026, Harpia AI Research
|
|
383
411
|
|
|
384
412
|
---
|
|
385
413
|
|
package/dist/VREFReader.d.ts
CHANGED
package/dist/VREFReader.js
CHANGED
|
@@ -51,6 +51,12 @@ class VREFReader {
|
|
|
51
51
|
if (!fs.existsSync(filePath)) {
|
|
52
52
|
throw new Error(`File not found: ${filePath}`);
|
|
53
53
|
}
|
|
54
|
+
if (options.validate) {
|
|
55
|
+
const validation = VREFReader.validate(filePath);
|
|
56
|
+
if (!validation.valid) {
|
|
57
|
+
throw new Error(`Invalid .vref file: ${validation.errors.join(', ')}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
54
60
|
const zip = new adm_zip_1.default(filePath);
|
|
55
61
|
const zipEntries = zip.getEntries();
|
|
56
62
|
// Find and parse manifest
|
|
@@ -181,5 +187,18 @@ class VREFReader {
|
|
|
181
187
|
return { valid: false, errors };
|
|
182
188
|
}
|
|
183
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* Extract all files from a .vref file to a target directory
|
|
192
|
+
*/
|
|
193
|
+
static extract(filePath, targetDir) {
|
|
194
|
+
if (!fs.existsSync(filePath)) {
|
|
195
|
+
throw new Error(`File not found: ${filePath}`);
|
|
196
|
+
}
|
|
197
|
+
if (!fs.existsSync(targetDir)) {
|
|
198
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
199
|
+
}
|
|
200
|
+
const zip = new adm_zip_1.default(filePath);
|
|
201
|
+
zip.extractAllTo(targetDir, true);
|
|
202
|
+
}
|
|
184
203
|
}
|
|
185
204
|
exports.VREFReader = VREFReader;
|
package/dist/VREFWriter.d.ts
CHANGED
package/dist/VREFWriter.js
CHANGED
|
@@ -125,13 +125,14 @@ class VREFWriter {
|
|
|
125
125
|
}
|
|
126
126
|
// Create manifest
|
|
127
127
|
const manifest = {
|
|
128
|
-
version: '1.0.
|
|
128
|
+
version: '1.0.2',
|
|
129
129
|
format: 'VREF',
|
|
130
|
-
fileName: path.basename(outputPath),
|
|
130
|
+
fileName: this.options.fileName || path.basename(outputPath),
|
|
131
131
|
imageCount: this.images.size,
|
|
132
132
|
images: imageMetadataList,
|
|
133
133
|
createdAt: new Date().toISOString(),
|
|
134
134
|
metadata: {
|
|
135
|
+
name: this.options.name,
|
|
135
136
|
description: this.options.description,
|
|
136
137
|
tags: this.options.tags,
|
|
137
138
|
author: this.options.author,
|
|
@@ -154,28 +155,56 @@ class VREFWriter {
|
|
|
154
155
|
* Validate image buffer by checking magic bytes
|
|
155
156
|
*/
|
|
156
157
|
isValidImageBuffer(buffer, format) {
|
|
157
|
-
if (buffer.length < 8)
|
|
158
|
+
if (!buffer || buffer.length < 8)
|
|
158
159
|
return false;
|
|
159
160
|
switch (format.toLowerCase()) {
|
|
160
161
|
case 'png':
|
|
161
|
-
return buffer
|
|
162
|
+
return (buffer.length >= 8 &&
|
|
163
|
+
buffer[0] === 0x89 &&
|
|
164
|
+
buffer[1] === 0x50 &&
|
|
165
|
+
buffer[2] === 0x4e &&
|
|
166
|
+
buffer[3] === 0x47);
|
|
162
167
|
case 'jpg':
|
|
163
168
|
case 'jpeg':
|
|
164
|
-
return buffer
|
|
169
|
+
return (buffer.length >= 3 &&
|
|
170
|
+
buffer[0] === 0xff &&
|
|
171
|
+
buffer[1] === 0xd8 &&
|
|
172
|
+
buffer[2] === 0xff);
|
|
165
173
|
case 'gif':
|
|
166
|
-
return buffer
|
|
174
|
+
return (buffer.length >= 6 &&
|
|
175
|
+
buffer[0] === 0x47 &&
|
|
176
|
+
buffer[1] === 0x49 &&
|
|
177
|
+
buffer[2] === 0x46 &&
|
|
178
|
+
buffer[3] === 0x38 &&
|
|
179
|
+
(buffer[4] === 0x37 || buffer[4] === 0x39) &&
|
|
180
|
+
buffer[5] === 0x61);
|
|
167
181
|
case 'webp':
|
|
168
|
-
return buffer
|
|
182
|
+
return (buffer.length >= 12 &&
|
|
183
|
+
buffer[0] === 0x52 &&
|
|
184
|
+
buffer[1] === 0x49 &&
|
|
185
|
+
buffer[2] === 0x46 &&
|
|
186
|
+
buffer[3] === 0x46 &&
|
|
187
|
+
buffer[8] === 0x57 &&
|
|
188
|
+
buffer[9] === 0x45 &&
|
|
189
|
+
buffer[10] === 0x42 &&
|
|
190
|
+
buffer[11] === 0x50);
|
|
169
191
|
case 'avif':
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
192
|
+
if (buffer.length < 16)
|
|
193
|
+
return false;
|
|
194
|
+
const ftypBox = buffer.toString('ascii', 4, 8);
|
|
195
|
+
if (ftypBox !== 'ftyp')
|
|
196
|
+
return false;
|
|
197
|
+
const majorBrand = buffer.toString('ascii', 8, 12);
|
|
198
|
+
if (majorBrand === 'avif' || majorBrand === 'avis')
|
|
199
|
+
return true;
|
|
200
|
+
const headerSlice = buffer.subarray(12, Math.min(buffer.length, 64)).toString('ascii');
|
|
201
|
+
return headerSlice.includes('avif') || headerSlice.includes('avis');
|
|
173
202
|
default:
|
|
174
203
|
return false;
|
|
175
204
|
}
|
|
176
205
|
}
|
|
177
206
|
/**
|
|
178
|
-
* Get image dimensions (
|
|
207
|
+
* Get image dimensions (supports PNG, JPEG, GIF, WebP)
|
|
179
208
|
*/
|
|
180
209
|
getImageDimensions(buffer, format) {
|
|
181
210
|
try {
|
|
@@ -185,8 +214,6 @@ class VREFWriter {
|
|
|
185
214
|
return { width, height };
|
|
186
215
|
}
|
|
187
216
|
if ((format === 'jpg' || format === 'jpeg') && buffer.length >= 4) {
|
|
188
|
-
// Basic JPEG dimension extraction (simplified)
|
|
189
|
-
// This is a simplified version; production code might use a library
|
|
190
217
|
let offset = 2;
|
|
191
218
|
while (offset < buffer.length) {
|
|
192
219
|
if (buffer[offset] !== 0xff)
|
|
@@ -202,6 +229,33 @@ class VREFWriter {
|
|
|
202
229
|
offset += segmentLength;
|
|
203
230
|
}
|
|
204
231
|
}
|
|
232
|
+
if (format === 'gif' && buffer.length >= 10) {
|
|
233
|
+
const width = buffer.readUInt16LE(6);
|
|
234
|
+
const height = buffer.readUInt16LE(8);
|
|
235
|
+
return { width, height };
|
|
236
|
+
}
|
|
237
|
+
if (format === 'webp' && buffer.length >= 30) {
|
|
238
|
+
const chunkType = buffer.toString('ascii', 12, 16);
|
|
239
|
+
if (chunkType === 'VP8 ' && buffer.length >= 30) {
|
|
240
|
+
const width = buffer.readUInt16LE(26) & 0x3fff;
|
|
241
|
+
const height = buffer.readUInt16LE(28) & 0x3fff;
|
|
242
|
+
return { width, height };
|
|
243
|
+
}
|
|
244
|
+
else if (chunkType === 'VP8L' && buffer.length >= 25) {
|
|
245
|
+
const b1 = buffer[21];
|
|
246
|
+
const b2 = buffer[22];
|
|
247
|
+
const b3 = buffer[23];
|
|
248
|
+
const b4 = buffer[24];
|
|
249
|
+
const width = 1 + (((b2 & 0x3f) << 8) | b1);
|
|
250
|
+
const height = 1 + (((b4 & 0x0f) << 10) | (b3 << 2) | ((b2 & 0xc0) >> 6));
|
|
251
|
+
return { width, height };
|
|
252
|
+
}
|
|
253
|
+
else if (chunkType === 'VP8X' && buffer.length >= 30) {
|
|
254
|
+
const width = 1 + buffer.readUIntLE(24, 3);
|
|
255
|
+
const height = 1 + buffer.readUIntLE(27, 3);
|
|
256
|
+
return { width, height };
|
|
257
|
+
}
|
|
258
|
+
}
|
|
205
259
|
}
|
|
206
260
|
catch (error) {
|
|
207
261
|
// If dimension extraction fails, just return undefined
|
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
/**
|
|
4
|
-
* VREF CLI - Command line interface for
|
|
4
|
+
* VREF CLI - Command line interface for .vref files
|
|
5
5
|
* Harpia AI Research
|
|
6
6
|
*/
|
|
7
7
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
@@ -41,47 +41,144 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
41
41
|
const fs = __importStar(require("fs"));
|
|
42
42
|
const path = __importStar(require("path"));
|
|
43
43
|
const VREFWriter_1 = require("./VREFWriter");
|
|
44
|
+
const VREFReader_1 = require("./VREFReader");
|
|
45
|
+
const CLI_VERSION = '1.0.2';
|
|
44
46
|
function showHelp() {
|
|
45
47
|
console.log(`
|
|
46
48
|
┌─────────────────────────────────────────────────┐
|
|
47
|
-
│ VREF CLI
|
|
49
|
+
│ VREF CLI v${CLI_VERSION} │
|
|
48
50
|
│ by Harpia AI Research │
|
|
49
51
|
│ https://harpiaresearch.cc │
|
|
50
52
|
└─────────────────────────────────────────────────┘
|
|
51
53
|
|
|
52
|
-
|
|
54
|
+
Standardized container for curated visual references in AI image generation
|
|
53
55
|
|
|
54
56
|
USAGE:
|
|
55
|
-
npx
|
|
56
|
-
|
|
57
|
-
ARGUMENTS:
|
|
58
|
-
<input> Path to image file or directory
|
|
57
|
+
npx @harpiaresearch/vref <input> [options]
|
|
58
|
+
vref <command> [arguments]
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
-
|
|
68
|
-
-
|
|
60
|
+
COMMANDS:
|
|
61
|
+
<input> [options] Create a .vref file from an image or directory
|
|
62
|
+
info, inspect <file.vref> Inspect metadata and images in a .vref file
|
|
63
|
+
validate <file.vref> Validate integrity and manifest of a .vref file
|
|
64
|
+
extract <file.vref> [dir] Extract all images from a .vref file
|
|
65
|
+
|
|
66
|
+
CREATION OPTIONS:
|
|
67
|
+
-o, --output <path> Output .vref file path (default: output.vref)
|
|
68
|
+
-n, --name <name> Name/title for the reference pack
|
|
69
|
+
-d, --desc <text> Description of the reference pack
|
|
70
|
+
-t, --tags <tags> Comma-separated tags
|
|
71
|
+
-a, --author <name> Author name
|
|
72
|
+
-l, --license <lic> License (e.g., CC-BY-4.0, MIT)
|
|
73
|
+
-r, --recursive Include subdirectories
|
|
74
|
+
-v, --version Show CLI version
|
|
75
|
+
-h, --help Show this help
|
|
69
76
|
|
|
70
77
|
EXAMPLES:
|
|
71
|
-
# Create from single image
|
|
72
|
-
npx create-vref image.png -o references.vref
|
|
73
|
-
|
|
74
78
|
# Create from directory
|
|
75
|
-
npx
|
|
76
|
-
|
|
77
|
-
#
|
|
78
|
-
npx
|
|
79
|
+
npx @harpiaresearch/vref ./images -o pack.vref -n "My Pack"
|
|
80
|
+
|
|
81
|
+
# Create with complete metadata
|
|
82
|
+
npx @harpiaresearch/vref ./sprites -o rpg-sprites.vref \\
|
|
79
83
|
-n "RPG Sprites" \\
|
|
80
84
|
-d "Character sprites for RPG games" \\
|
|
81
85
|
-t "rpg,sprites,pixelart" \\
|
|
82
86
|
-a "Your Name" \\
|
|
83
87
|
-l "CC-BY-4.0"
|
|
84
|
-
|
|
88
|
+
|
|
89
|
+
# Inspect an existing .vref file
|
|
90
|
+
vref info references.vref
|
|
91
|
+
|
|
92
|
+
# Validate file integrity
|
|
93
|
+
vref validate references.vref
|
|
94
|
+
|
|
95
|
+
# Extract images
|
|
96
|
+
vref extract references.vref ./extracted-images
|
|
97
|
+
`);
|
|
98
|
+
}
|
|
99
|
+
function handleValidate(filePath) {
|
|
100
|
+
if (!filePath) {
|
|
101
|
+
console.error('❌ Error: Please specify a .vref file to validate');
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
console.log(`🔍 Validating ${filePath}...`);
|
|
105
|
+
const result = VREFReader_1.VREFReader.validate(filePath);
|
|
106
|
+
if (result.valid) {
|
|
107
|
+
const manifest = VREFReader_1.VREFReader.readManifest(filePath);
|
|
108
|
+
console.log(`✅ Valid .vref file!`);
|
|
109
|
+
console.log(` Format: ${manifest.format} (v${manifest.version})`);
|
|
110
|
+
console.log(` Images: ${manifest.imageCount}`);
|
|
111
|
+
if (manifest.metadata?.name)
|
|
112
|
+
console.log(` Name: ${manifest.metadata.name}`);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
console.error(`❌ Validation failed with ${result.errors.length} error(s):`);
|
|
116
|
+
result.errors.forEach(err => console.error(` - ${err}`));
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function handleInfo(filePath) {
|
|
121
|
+
if (!filePath) {
|
|
122
|
+
console.error('❌ Error: Please specify a .vref file to inspect');
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
try {
|
|
126
|
+
const manifest = VREFReader_1.VREFReader.readManifest(filePath);
|
|
127
|
+
const stats = fs.statSync(filePath);
|
|
128
|
+
const sizeMB = (stats.size / (1024 * 1024)).toFixed(2);
|
|
129
|
+
console.log(`\n📦 File: ${path.basename(filePath)} (${sizeMB} MB)`);
|
|
130
|
+
console.log(` Format: ${manifest.format} v${manifest.version}`);
|
|
131
|
+
console.log(` Created at: ${manifest.createdAt}`);
|
|
132
|
+
console.log(` Total images: ${manifest.imageCount}`);
|
|
133
|
+
if (manifest.metadata) {
|
|
134
|
+
console.log('\n📋 Metadata:');
|
|
135
|
+
if (manifest.metadata.name)
|
|
136
|
+
console.log(` Name: ${manifest.metadata.name}`);
|
|
137
|
+
if (manifest.metadata.description)
|
|
138
|
+
console.log(` Description: ${manifest.metadata.description}`);
|
|
139
|
+
if (manifest.metadata.tags && manifest.metadata.tags.length > 0) {
|
|
140
|
+
console.log(` Tags: ${manifest.metadata.tags.join(', ')}`);
|
|
141
|
+
}
|
|
142
|
+
if (manifest.metadata.author)
|
|
143
|
+
console.log(` Author: ${manifest.metadata.author}`);
|
|
144
|
+
if (manifest.metadata.license)
|
|
145
|
+
console.log(` License: ${manifest.metadata.license}`);
|
|
146
|
+
}
|
|
147
|
+
if (manifest.images.length > 0) {
|
|
148
|
+
console.log('\n🖼️ Sample of contained images:');
|
|
149
|
+
const previewCount = Math.min(manifest.images.length, 5);
|
|
150
|
+
for (let i = 0; i < previewCount; i++) {
|
|
151
|
+
const img = manifest.images[i];
|
|
152
|
+
const dim = img.width && img.height ? ` (${img.width}x${img.height})` : '';
|
|
153
|
+
const sizeKB = (img.size / 1024).toFixed(1);
|
|
154
|
+
console.log(` - ${img.path} [${img.format.toUpperCase()}]${dim} - ${sizeKB} KB`);
|
|
155
|
+
}
|
|
156
|
+
if (manifest.images.length > previewCount) {
|
|
157
|
+
console.log(` ... and ${manifest.images.length - previewCount} more`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
console.log();
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
console.error(`❌ Error inspecting file: ${error.message}`);
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function handleExtract(filePath, outputDir) {
|
|
168
|
+
if (!filePath) {
|
|
169
|
+
console.error('❌ Error: Please specify a .vref file to extract');
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
const targetDir = outputDir || path.join(process.cwd(), path.basename(filePath, '.vref') + '_extracted');
|
|
173
|
+
try {
|
|
174
|
+
console.log(`📦 Extracting ${filePath} to ${targetDir}...`);
|
|
175
|
+
VREFReader_1.VREFReader.extract(filePath, targetDir);
|
|
176
|
+
console.log(`✅ Extracted successfully to ${targetDir}`);
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
console.error(`❌ Extraction error: ${error.message}`);
|
|
180
|
+
process.exit(1);
|
|
181
|
+
}
|
|
85
182
|
}
|
|
86
183
|
function parseArgs(args) {
|
|
87
184
|
const options = {
|
|
@@ -102,6 +199,11 @@ function parseArgs(args) {
|
|
|
102
199
|
showHelp();
|
|
103
200
|
process.exit(0);
|
|
104
201
|
break;
|
|
202
|
+
case '-v':
|
|
203
|
+
case '--version':
|
|
204
|
+
console.log(`v${CLI_VERSION}`);
|
|
205
|
+
process.exit(0);
|
|
206
|
+
break;
|
|
105
207
|
case '-o':
|
|
106
208
|
case '--output':
|
|
107
209
|
options.output = args[++i];
|
|
@@ -117,7 +219,7 @@ function parseArgs(args) {
|
|
|
117
219
|
break;
|
|
118
220
|
case '-t':
|
|
119
221
|
case '--tags':
|
|
120
|
-
options.tags = args[++i]
|
|
222
|
+
options.tags = args[++i]?.split(',').map((t) => t.trim());
|
|
121
223
|
break;
|
|
122
224
|
case '-a':
|
|
123
225
|
case '--author':
|
|
@@ -132,7 +234,7 @@ function parseArgs(args) {
|
|
|
132
234
|
options.recursive = true;
|
|
133
235
|
break;
|
|
134
236
|
default:
|
|
135
|
-
if (!arg.startsWith('-')) {
|
|
237
|
+
if (!arg.startsWith('-') && !options.input) {
|
|
136
238
|
options.input = arg;
|
|
137
239
|
}
|
|
138
240
|
break;
|
|
@@ -146,10 +248,31 @@ function main() {
|
|
|
146
248
|
showHelp();
|
|
147
249
|
process.exit(0);
|
|
148
250
|
}
|
|
251
|
+
const firstArg = args[0];
|
|
252
|
+
if (firstArg === 'validate') {
|
|
253
|
+
handleValidate(args[1]);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
if (firstArg === 'info' || firstArg === 'inspect') {
|
|
257
|
+
handleInfo(args[1]);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
if (firstArg === 'extract') {
|
|
261
|
+
handleExtract(args[1], args[2]);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
if (firstArg === '-h' || firstArg === '--help') {
|
|
265
|
+
showHelp();
|
|
266
|
+
process.exit(0);
|
|
267
|
+
}
|
|
268
|
+
if (firstArg === '-v' || firstArg === '--version') {
|
|
269
|
+
console.log(`v${CLI_VERSION}`);
|
|
270
|
+
process.exit(0);
|
|
271
|
+
}
|
|
149
272
|
const options = parseArgs(args);
|
|
150
273
|
if (!options.input) {
|
|
151
274
|
console.error('❌ Error: No input specified');
|
|
152
|
-
console.log('Run "npx
|
|
275
|
+
console.log('Run "npx @harpiaresearch/vref --help" for usage information');
|
|
153
276
|
process.exit(1);
|
|
154
277
|
}
|
|
155
278
|
if (!fs.existsSync(options.input)) {
|
|
@@ -157,13 +280,13 @@ function main() {
|
|
|
157
280
|
process.exit(1);
|
|
158
281
|
}
|
|
159
282
|
console.log('┌─────────────────────────────────────────────────┐');
|
|
160
|
-
console.log(
|
|
283
|
+
console.log(`│ VREF CLI v${CLI_VERSION} │`);
|
|
161
284
|
console.log('│ by Harpia AI Research │');
|
|
162
285
|
console.log('└─────────────────────────────────────────────────┘\n');
|
|
163
286
|
try {
|
|
164
|
-
const fileName = options.name || path.basename(options.output, '.vref');
|
|
165
287
|
const writer = new VREFWriter_1.VREFWriter({
|
|
166
|
-
fileName: options.output,
|
|
288
|
+
fileName: path.basename(options.output),
|
|
289
|
+
name: options.name,
|
|
167
290
|
description: options.description,
|
|
168
291
|
tags: options.tags,
|
|
169
292
|
author: options.author,
|
package/dist/types.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ export interface VREFManifest {
|
|
|
23
23
|
createdAt: string;
|
|
24
24
|
/** Optional metadata */
|
|
25
25
|
metadata?: {
|
|
26
|
+
/** Human-readable title/name of the reference pack */
|
|
27
|
+
name?: string;
|
|
26
28
|
/** Description of the reference pack */
|
|
27
29
|
description?: string;
|
|
28
30
|
/** Tags for categorization */
|
|
@@ -54,8 +56,10 @@ export interface ImageMetadata {
|
|
|
54
56
|
* Options for creating a VREF file
|
|
55
57
|
*/
|
|
56
58
|
export interface VREFCreateOptions {
|
|
57
|
-
/**
|
|
58
|
-
|
|
59
|
+
/** Optional name/title for the reference pack */
|
|
60
|
+
name?: string;
|
|
61
|
+
/** Name for the output .vref file (optional, defaults to output path file name) */
|
|
62
|
+
fileName?: string;
|
|
59
63
|
/** Optional description */
|
|
60
64
|
description?: string;
|
|
61
65
|
/** Optional tags */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@harpiaresearch/vref",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Visual Reference Format - Standardized container for curated visual references in AI image generation",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"LICENSE"
|
|
11
11
|
],
|
|
12
12
|
"bin": {
|
|
13
|
-
"create-vref": "
|
|
14
|
-
"vref": "
|
|
13
|
+
"create-vref": "dist/cli.js",
|
|
14
|
+
"vref": "dist/cli.js"
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
17
|
"build": "tsc",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"license": "BSD-3-Clause",
|
|
33
33
|
"repository": {
|
|
34
34
|
"type": "git",
|
|
35
|
-
"url": "https://github.com/Harpia-AI-Research/vref"
|
|
35
|
+
"url": "git+https://github.com/Harpia-AI-Research/vref.git"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"adm-zip": "^0.5.10"
|