@intactfile/cli 0.1.0 → 0.2.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/dist/index.js +68 -3
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -7,12 +7,13 @@ import { mkdirSync, writeFileSync } from "node:fs";
|
|
|
7
7
|
import { basename, dirname, extname, join, parse } from "node:path";
|
|
8
8
|
import { createInterface } from "node:readline";
|
|
9
9
|
import { Command } from "commander";
|
|
10
|
-
import { ApiError, balance, clearAuth, consume, EntitlementError, getToken, login as apiLogin, magic as apiMagic, recover as apiRecover, repairPath, diagnosePath, requireBusiness, setToken, UnsupportedError, } from "@intactfile/node-core";
|
|
10
|
+
import { ApiError, balance, clearAuth, consume, EntitlementError, ensureLicense, getLicenseStatus, getToken, login as apiLogin, magic as apiMagic, recover as apiRecover, repairPath, diagnosePath, requireBusiness, setToken, UnsupportedError, } from "@intactfile/node-core";
|
|
11
|
+
import { generateRepairReportPdf } from "@intactfile/report";
|
|
11
12
|
const program = new Command();
|
|
12
13
|
program
|
|
13
14
|
.name("intactfile")
|
|
14
15
|
.description("Repair corrupted files locally — your files never leave your machine.")
|
|
15
|
-
.version("0.
|
|
16
|
+
.version("0.2.0");
|
|
16
17
|
/* ------------------------------- helpers ------------------------------- */
|
|
17
18
|
function ask(query) {
|
|
18
19
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -42,6 +43,8 @@ const OUT_EXT = {
|
|
|
42
43
|
png: ".png",
|
|
43
44
|
sqlite: ".sqlite",
|
|
44
45
|
archive: "",
|
|
46
|
+
audio: ".wav",
|
|
47
|
+
avi: ".avi",
|
|
45
48
|
};
|
|
46
49
|
function defaultOut(input, family) {
|
|
47
50
|
const p = parse(input);
|
|
@@ -85,6 +88,34 @@ function writeResult(input, out, r) {
|
|
|
85
88
|
writeFileSync(dest, r.bytes);
|
|
86
89
|
return [dest];
|
|
87
90
|
}
|
|
91
|
+
/** Map a repair result into the report package's minimal input shape. */
|
|
92
|
+
function toReportInput(input, r) {
|
|
93
|
+
const report = r.report;
|
|
94
|
+
const num = (v) => {
|
|
95
|
+
const n = typeof v === "number" ? v : v == null ? NaN : Number(v);
|
|
96
|
+
return Number.isFinite(n) ? n : undefined;
|
|
97
|
+
};
|
|
98
|
+
const base = {
|
|
99
|
+
fileName: basename(input),
|
|
100
|
+
family: r.family,
|
|
101
|
+
outcome: report.outcome != null ? String(report.outcome) : undefined,
|
|
102
|
+
damageClass: report.damageClass != null ? String(report.damageClass) : undefined,
|
|
103
|
+
bytesIn: num(report.bytesIn),
|
|
104
|
+
bytesOut: num(report.bytesOut),
|
|
105
|
+
notes: Array.isArray(report.notes) ? report.notes.map((n) => String(n)) : undefined,
|
|
106
|
+
};
|
|
107
|
+
if (r.kind === "archive") {
|
|
108
|
+
base.files = r.files.map((f) => ({ name: f.name, status: f.status }));
|
|
109
|
+
}
|
|
110
|
+
return base;
|
|
111
|
+
}
|
|
112
|
+
/** Generate and write a white-label PDF repair report; prints the path. */
|
|
113
|
+
async function writeReportPdf(input, r, path, company) {
|
|
114
|
+
const bytes = await generateRepairReportPdf(toReportInput(input, r), company ? { company } : {});
|
|
115
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
116
|
+
writeFileSync(path, bytes);
|
|
117
|
+
console.log(`✓ Report: ${path}`);
|
|
118
|
+
}
|
|
88
119
|
/* -------------------------------- login -------------------------------- */
|
|
89
120
|
program
|
|
90
121
|
.command("login")
|
|
@@ -147,6 +178,27 @@ program
|
|
|
147
178
|
handle(e);
|
|
148
179
|
}
|
|
149
180
|
});
|
|
181
|
+
program
|
|
182
|
+
.command("license")
|
|
183
|
+
.description("Fetch and apply your offline Business license (used by repair and the SDK).")
|
|
184
|
+
.option("--refresh", "force a fresh license even if the cached one is still valid")
|
|
185
|
+
.action(async (opts) => {
|
|
186
|
+
try {
|
|
187
|
+
await requireBusiness();
|
|
188
|
+
const token = getToken();
|
|
189
|
+
if (token)
|
|
190
|
+
await ensureLicense(token, { force: !!opts.refresh });
|
|
191
|
+
const status = await getLicenseStatus();
|
|
192
|
+
if (!status.licensed) {
|
|
193
|
+
return die(`Couldn't apply a license (${status.reason ?? "unknown"}).`);
|
|
194
|
+
}
|
|
195
|
+
console.log(`✓ License active (${status.tier}) — valid until ${status.expiresAt?.slice(0, 10)}.`);
|
|
196
|
+
console.log(" The CLI, MCP server, and SDK use it automatically; it works offline until then.");
|
|
197
|
+
}
|
|
198
|
+
catch (e) {
|
|
199
|
+
handle(e);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
150
202
|
function summarize(sub) {
|
|
151
203
|
if (!sub)
|
|
152
204
|
return console.log("Plan: none (no active subscription).");
|
|
@@ -182,13 +234,18 @@ program
|
|
|
182
234
|
.option("-o, --out <path>", "output path (or directory for archives)")
|
|
183
235
|
.option("-r, --reference <clip>", "healthy reference clip/photo (missing-moov video, JPEG donor)")
|
|
184
236
|
.option("-p, --password <pw>", "archive password (RAR/7z)")
|
|
237
|
+
.option("--report <path.pdf>", "also write a white-label PDF repair report to this path")
|
|
238
|
+
.option("--company <name>", "company name for the white-label report header")
|
|
185
239
|
.action(async (file, opts) => {
|
|
186
240
|
try {
|
|
187
241
|
const sub = await requireBusiness();
|
|
188
242
|
if (sub.monthlyRemaining <= 0) {
|
|
189
243
|
return die("Monthly repair allowance exhausted — it resets on your billing cycle.");
|
|
190
244
|
}
|
|
191
|
-
const r = await repairPath(file, {
|
|
245
|
+
const r = await repairPath(file, {
|
|
246
|
+
referencePath: opts.reference,
|
|
247
|
+
password: opts.password,
|
|
248
|
+
});
|
|
192
249
|
printReport(r.family, r.report);
|
|
193
250
|
if (!r.usable) {
|
|
194
251
|
return die("Couldn't produce a usable result — nothing was charged.");
|
|
@@ -196,6 +253,8 @@ program
|
|
|
196
253
|
const written = writeResult(file, opts.out, r);
|
|
197
254
|
await meter();
|
|
198
255
|
console.log(`✓ Wrote:\n${written.map((w) => ` ${w}`).join("\n")}`);
|
|
256
|
+
if (opts.report)
|
|
257
|
+
await writeReportPdf(file, r, opts.report, opts.company);
|
|
199
258
|
}
|
|
200
259
|
catch (e) {
|
|
201
260
|
handle(e);
|
|
@@ -206,6 +265,8 @@ program
|
|
|
206
265
|
.command("batch <files...>")
|
|
207
266
|
.description("Repair up to 100 files (Business plan). Each is metered separately.")
|
|
208
267
|
.option("-o, --outdir <dir>", "directory to write results into")
|
|
268
|
+
.option("--report-dir <dir>", "also write a white-label PDF repair report per file into this dir")
|
|
269
|
+
.option("--company <name>", "company name for the white-label report header")
|
|
209
270
|
.action(async (files, opts) => {
|
|
210
271
|
try {
|
|
211
272
|
await requireBusiness();
|
|
@@ -234,6 +295,10 @@ program
|
|
|
234
295
|
const written = writeResult(file, out, r);
|
|
235
296
|
await meter();
|
|
236
297
|
console.log(`✓ ${basename(file)} → ${written[0] ?? "(extracted)"}`);
|
|
298
|
+
if (opts.reportDir) {
|
|
299
|
+
const pdfPath = join(opts.reportDir, `${parse(file).name}.report.pdf`);
|
|
300
|
+
await writeReportPdf(file, r, pdfPath, opts.company);
|
|
301
|
+
}
|
|
237
302
|
ok++;
|
|
238
303
|
}
|
|
239
304
|
catch (e) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intactfile/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "IntactFile CLI — repair corrupted files locally (video, ZIP/Office, PDF, JPEG, PNG, SQLite, RAR/7z). Your files never leave your machine. Business plan for repairs; diagnosis is free.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"commander": "^12.1.0",
|
|
18
|
-
"@intactfile/node-core": "0.
|
|
18
|
+
"@intactfile/node-core": "0.2.0",
|
|
19
|
+
"@intactfile/report": "0.1.0"
|
|
19
20
|
},
|
|
20
21
|
"devDependencies": {
|
|
21
22
|
"@types/node": "^22.15.0",
|