@aramantos/provechain-cli 1.0.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/LICENSE +21 -0
- package/dist/index.js +850 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 John Doyle / Aramantos Digital
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,850 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Command as Command10 } from "commander";
|
|
5
|
+
|
|
6
|
+
// src/commands/init.ts
|
|
7
|
+
import { Command } from "commander";
|
|
8
|
+
import chalk from "chalk";
|
|
9
|
+
|
|
10
|
+
// src/lib/config.ts
|
|
11
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
12
|
+
import { join } from "path";
|
|
13
|
+
import { parse } from "yaml";
|
|
14
|
+
var DEFAULT_CONFIG = `# ProveChain Configuration
|
|
15
|
+
# https://provechain.aramantos.dev
|
|
16
|
+
|
|
17
|
+
# File extensions to include in snapshots
|
|
18
|
+
include_extensions:
|
|
19
|
+
- .py
|
|
20
|
+
- .js
|
|
21
|
+
- .ts
|
|
22
|
+
- .tsx
|
|
23
|
+
- .jsx
|
|
24
|
+
- .java
|
|
25
|
+
- .go
|
|
26
|
+
- .rs
|
|
27
|
+
- .c
|
|
28
|
+
- .cpp
|
|
29
|
+
- .h
|
|
30
|
+
- .cs
|
|
31
|
+
- .rb
|
|
32
|
+
- .php
|
|
33
|
+
- .swift
|
|
34
|
+
- .kt
|
|
35
|
+
- .md
|
|
36
|
+
- .yaml
|
|
37
|
+
- .yml
|
|
38
|
+
- .json
|
|
39
|
+
- .toml
|
|
40
|
+
- .sql
|
|
41
|
+
- .sh
|
|
42
|
+
- .css
|
|
43
|
+
- .html
|
|
44
|
+
- .svg
|
|
45
|
+
|
|
46
|
+
# Paths to ignore (relative to project root)
|
|
47
|
+
ignore_paths:
|
|
48
|
+
- .git
|
|
49
|
+
- .venv
|
|
50
|
+
- venv
|
|
51
|
+
- node_modules
|
|
52
|
+
- __pycache__
|
|
53
|
+
- dist
|
|
54
|
+
- build
|
|
55
|
+
- .next
|
|
56
|
+
- target
|
|
57
|
+
- provechain
|
|
58
|
+
- .provechain
|
|
59
|
+
`;
|
|
60
|
+
var DEFAULT_EXTENSIONS = [
|
|
61
|
+
".py",
|
|
62
|
+
".js",
|
|
63
|
+
".ts",
|
|
64
|
+
".tsx",
|
|
65
|
+
".jsx",
|
|
66
|
+
".java",
|
|
67
|
+
".go",
|
|
68
|
+
".rs",
|
|
69
|
+
".c",
|
|
70
|
+
".cpp",
|
|
71
|
+
".h",
|
|
72
|
+
".cs",
|
|
73
|
+
".rb",
|
|
74
|
+
".php",
|
|
75
|
+
".swift",
|
|
76
|
+
".kt",
|
|
77
|
+
".md",
|
|
78
|
+
".yaml",
|
|
79
|
+
".yml",
|
|
80
|
+
".json",
|
|
81
|
+
".toml",
|
|
82
|
+
".sql",
|
|
83
|
+
".sh",
|
|
84
|
+
".css",
|
|
85
|
+
".html",
|
|
86
|
+
".svg"
|
|
87
|
+
];
|
|
88
|
+
var DEFAULT_IGNORE = [
|
|
89
|
+
".git",
|
|
90
|
+
".venv",
|
|
91
|
+
"venv",
|
|
92
|
+
"node_modules",
|
|
93
|
+
"__pycache__",
|
|
94
|
+
"dist",
|
|
95
|
+
"build",
|
|
96
|
+
".next",
|
|
97
|
+
"target",
|
|
98
|
+
"provechain",
|
|
99
|
+
".provechain"
|
|
100
|
+
];
|
|
101
|
+
function loadConfig(projectRoot) {
|
|
102
|
+
const configPath = join(projectRoot, "provechain.yaml");
|
|
103
|
+
if (!existsSync(configPath)) {
|
|
104
|
+
return {
|
|
105
|
+
include_extensions: DEFAULT_EXTENSIONS,
|
|
106
|
+
ignore_paths: DEFAULT_IGNORE
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
110
|
+
const parsed = parse(raw);
|
|
111
|
+
return {
|
|
112
|
+
include_extensions: parsed.include_extensions || DEFAULT_EXTENSIONS,
|
|
113
|
+
ignore_paths: parsed.ignore_paths || DEFAULT_IGNORE
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function createDefaultConfig(projectRoot, force) {
|
|
117
|
+
const configPath = join(projectRoot, "provechain.yaml");
|
|
118
|
+
if (existsSync(configPath) && !force) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
writeFileSync(configPath, DEFAULT_CONFIG, "utf-8");
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/commands/init.ts
|
|
126
|
+
var initCommand = new Command("init").description("Initialize ProveChain in current project").option("--force", "Overwrite existing config").action((opts) => {
|
|
127
|
+
const root = opts.parent?.opts()?.projectRoot || process.cwd();
|
|
128
|
+
const json = opts.parent?.opts()?.json || false;
|
|
129
|
+
const created = createDefaultConfig(root, opts.force || false);
|
|
130
|
+
if (!created) {
|
|
131
|
+
if (json) {
|
|
132
|
+
console.log(JSON.stringify({ success: false, error: "provechain.yaml already exists. Use --force to overwrite." }));
|
|
133
|
+
} else {
|
|
134
|
+
console.log(chalk.red("provechain.yaml already exists.") + " Use --force to overwrite.");
|
|
135
|
+
}
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
if (json) {
|
|
139
|
+
console.log(JSON.stringify({ success: true, message: "ProveChain initialized" }));
|
|
140
|
+
} else {
|
|
141
|
+
console.log();
|
|
142
|
+
console.log(chalk.green.bold("ProveChain Initialized!"));
|
|
143
|
+
console.log(chalk.dim(`Config: provechain.yaml`));
|
|
144
|
+
console.log();
|
|
145
|
+
console.log(chalk.cyan.bold("Next steps:"));
|
|
146
|
+
console.log(` ${chalk.cyan("1.")} Edit provechain.yaml to customize settings`);
|
|
147
|
+
console.log(` ${chalk.cyan("2.")} Run: ${chalk.green('provechain snapshot "Initial commit"')}`);
|
|
148
|
+
console.log(` ${chalk.cyan("3.")} Add ${chalk.yellow("provechain/")} to your .gitignore`);
|
|
149
|
+
console.log();
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// src/commands/snapshot.ts
|
|
154
|
+
import { Command as Command2 } from "commander";
|
|
155
|
+
import chalk2 from "chalk";
|
|
156
|
+
import ora from "ora";
|
|
157
|
+
|
|
158
|
+
// src/lib/hasher.ts
|
|
159
|
+
import { createHash } from "crypto";
|
|
160
|
+
import { readFileSync as readFileSync2, readdirSync, statSync } from "fs";
|
|
161
|
+
import { join as join2, relative, extname } from "path";
|
|
162
|
+
function hashFile(filePath) {
|
|
163
|
+
const buffer = readFileSync2(filePath);
|
|
164
|
+
return createHash("sha256").update(buffer).digest("hex");
|
|
165
|
+
}
|
|
166
|
+
function hashFiles(projectRoot, config, onProgress) {
|
|
167
|
+
const hashes = [];
|
|
168
|
+
let skipped = 0;
|
|
169
|
+
const extensionSet = new Set(config.include_extensions);
|
|
170
|
+
const ignoreSet = new Set(config.ignore_paths);
|
|
171
|
+
function walk(dir) {
|
|
172
|
+
let entries;
|
|
173
|
+
try {
|
|
174
|
+
entries = readdirSync(dir);
|
|
175
|
+
} catch {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
for (const entry of entries) {
|
|
179
|
+
const relPath = relative(projectRoot, join2(dir, entry));
|
|
180
|
+
const topLevel = relPath.split(/[/\\]/)[0];
|
|
181
|
+
if (ignoreSet.has(topLevel) || ignoreSet.has(entry)) {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
if (entry.startsWith(".")) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const fullPath = join2(dir, entry);
|
|
188
|
+
let stat;
|
|
189
|
+
try {
|
|
190
|
+
stat = statSync(fullPath);
|
|
191
|
+
} catch {
|
|
192
|
+
skipped++;
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (stat.isDirectory()) {
|
|
196
|
+
walk(fullPath);
|
|
197
|
+
} else if (stat.isFile()) {
|
|
198
|
+
const ext = extname(entry).toLowerCase();
|
|
199
|
+
if (!extensionSet.has(ext)) {
|
|
200
|
+
skipped++;
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
try {
|
|
204
|
+
const hash = hashFile(fullPath);
|
|
205
|
+
const normalizedPath = relative(projectRoot, fullPath).replace(/\\/g, "/");
|
|
206
|
+
hashes.push({
|
|
207
|
+
path: normalizedPath,
|
|
208
|
+
hash,
|
|
209
|
+
size: stat.size
|
|
210
|
+
});
|
|
211
|
+
if (onProgress) {
|
|
212
|
+
onProgress(hashes.length, 0, normalizedPath);
|
|
213
|
+
}
|
|
214
|
+
} catch {
|
|
215
|
+
skipped++;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
walk(projectRoot);
|
|
221
|
+
hashes.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
222
|
+
return { hashes, skipped };
|
|
223
|
+
}
|
|
224
|
+
function generateProofHash(fileHashes) {
|
|
225
|
+
const sorted = [...fileHashes].sort(
|
|
226
|
+
(a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0
|
|
227
|
+
);
|
|
228
|
+
const manifest = sorted.map((f) => `${f.path}:${f.hash}`).join("\n");
|
|
229
|
+
return createHash("sha256").update(manifest).digest("hex");
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// src/lib/proof.ts
|
|
233
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, appendFileSync, mkdirSync, readdirSync as readdirSync2, existsSync as existsSync2 } from "fs";
|
|
234
|
+
import { join as join3 } from "path";
|
|
235
|
+
import { randomUUID } from "crypto";
|
|
236
|
+
var PROOFS_DIR = "provechain/proofs";
|
|
237
|
+
var LEDGER_FILE = "provechain/innovation_ledger.ndjson";
|
|
238
|
+
function ensureProofsDir(projectRoot) {
|
|
239
|
+
const dir = join3(projectRoot, PROOFS_DIR);
|
|
240
|
+
mkdirSync(dir, { recursive: true });
|
|
241
|
+
return dir;
|
|
242
|
+
}
|
|
243
|
+
function createProof(projectRoot, fileHashes, skipped, description) {
|
|
244
|
+
const proofId = generateProofHash(fileHashes);
|
|
245
|
+
const fileHashMap = {};
|
|
246
|
+
for (const fh of fileHashes) {
|
|
247
|
+
fileHashMap[fh.path] = fh.hash;
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
proof_id: proofId,
|
|
251
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
252
|
+
description,
|
|
253
|
+
project_root: projectRoot,
|
|
254
|
+
total_files: fileHashes.length + skipped,
|
|
255
|
+
files_processed: fileHashes.length,
|
|
256
|
+
files_skipped: skipped,
|
|
257
|
+
file_hashes: fileHashMap,
|
|
258
|
+
files: fileHashes,
|
|
259
|
+
hash_version: 1
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
function saveProof(projectRoot, proof) {
|
|
263
|
+
const dir = ensureProofsDir(projectRoot);
|
|
264
|
+
const dateStr = proof.timestamp.replace(/:/g, "-").replace(/\./g, "-");
|
|
265
|
+
const filename = `proof_${dateStr}.json`;
|
|
266
|
+
const filePath = join3(dir, filename);
|
|
267
|
+
writeFileSync2(filePath, JSON.stringify(proof, null, 2), "utf-8");
|
|
268
|
+
return filePath;
|
|
269
|
+
}
|
|
270
|
+
function loadProof(filePath) {
|
|
271
|
+
const raw = readFileSync3(filePath, "utf-8");
|
|
272
|
+
return JSON.parse(raw);
|
|
273
|
+
}
|
|
274
|
+
function listProofs(projectRoot) {
|
|
275
|
+
const dir = join3(projectRoot, PROOFS_DIR);
|
|
276
|
+
if (!existsSync2(dir)) return [];
|
|
277
|
+
const files = readdirSync2(dir).filter((f) => f.startsWith("proof_") && f.endsWith(".json")).sort().reverse();
|
|
278
|
+
return files.map((file) => ({
|
|
279
|
+
proof: loadProof(join3(dir, file)),
|
|
280
|
+
file
|
|
281
|
+
}));
|
|
282
|
+
}
|
|
283
|
+
function logEvent(projectRoot, eventType, description, metadata) {
|
|
284
|
+
const ledgerPath = join3(projectRoot, LEDGER_FILE);
|
|
285
|
+
mkdirSync(join3(projectRoot, "provechain"), { recursive: true });
|
|
286
|
+
const entry = {
|
|
287
|
+
event_id: randomUUID(),
|
|
288
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
289
|
+
event_type: eventType,
|
|
290
|
+
description,
|
|
291
|
+
...metadata
|
|
292
|
+
};
|
|
293
|
+
const line = JSON.stringify(entry) + "\n";
|
|
294
|
+
appendFileSync(ledgerPath, line, "utf-8");
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// src/lib/auth.ts
|
|
298
|
+
import { createClient } from "@supabase/supabase-js";
|
|
299
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync3, unlinkSync } from "fs";
|
|
300
|
+
import { join as join4 } from "path";
|
|
301
|
+
import { homedir } from "os";
|
|
302
|
+
var CORE_SUPABASE_URL = "https://kxhesmrmfawujrwrrres.supabase.co";
|
|
303
|
+
var CORE_SUPABASE_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Imt4aGVzbXJtZmF3dWpyd3JycmVzIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Mzc4MzIyMjUsImV4cCI6MjA1MzQwODIyNX0.2PNjBJOXJGUMiP8foWQxZKHAHVNjdlQaBe0K8skVFaY";
|
|
304
|
+
var CONFIG_DIR = join4(homedir(), ".provechain");
|
|
305
|
+
var CREDENTIALS_FILE = join4(CONFIG_DIR, "credentials.json");
|
|
306
|
+
function getClient() {
|
|
307
|
+
return createClient(CORE_SUPABASE_URL, CORE_SUPABASE_ANON_KEY);
|
|
308
|
+
}
|
|
309
|
+
async function login(email, password) {
|
|
310
|
+
const supabase = getClient();
|
|
311
|
+
const { data, error } = await supabase.auth.signInWithPassword({ email, password });
|
|
312
|
+
if (error) throw new Error(error.message);
|
|
313
|
+
if (!data.session || !data.user) throw new Error("Login failed");
|
|
314
|
+
const session = {
|
|
315
|
+
access_token: data.session.access_token,
|
|
316
|
+
refresh_token: data.session.refresh_token,
|
|
317
|
+
expires_at: data.session.expires_at || 0,
|
|
318
|
+
user: { id: data.user.id, email: data.user.email || email }
|
|
319
|
+
};
|
|
320
|
+
mkdirSync2(CONFIG_DIR, { recursive: true });
|
|
321
|
+
writeFileSync3(CREDENTIALS_FILE, JSON.stringify(session, null, 2), { mode: 384 });
|
|
322
|
+
return session;
|
|
323
|
+
}
|
|
324
|
+
function logout() {
|
|
325
|
+
if (existsSync3(CREDENTIALS_FILE)) {
|
|
326
|
+
unlinkSync(CREDENTIALS_FILE);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
function getStoredSession() {
|
|
330
|
+
if (!existsSync3(CREDENTIALS_FILE)) return null;
|
|
331
|
+
try {
|
|
332
|
+
const raw = readFileSync4(CREDENTIALS_FILE, "utf-8");
|
|
333
|
+
return JSON.parse(raw);
|
|
334
|
+
} catch {
|
|
335
|
+
return null;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
async function refreshSession() {
|
|
339
|
+
const stored = getStoredSession();
|
|
340
|
+
if (!stored) return null;
|
|
341
|
+
const supabase = getClient();
|
|
342
|
+
const { data, error } = await supabase.auth.setSession({
|
|
343
|
+
access_token: stored.access_token,
|
|
344
|
+
refresh_token: stored.refresh_token
|
|
345
|
+
});
|
|
346
|
+
if (error || !data.session) {
|
|
347
|
+
logout();
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
const session = {
|
|
351
|
+
access_token: data.session.access_token,
|
|
352
|
+
refresh_token: data.session.refresh_token,
|
|
353
|
+
expires_at: data.session.expires_at || 0,
|
|
354
|
+
user: stored.user
|
|
355
|
+
};
|
|
356
|
+
writeFileSync3(CREDENTIALS_FILE, JSON.stringify(session, null, 2), { mode: 384 });
|
|
357
|
+
return session;
|
|
358
|
+
}
|
|
359
|
+
async function getValidSession() {
|
|
360
|
+
const stored = getStoredSession();
|
|
361
|
+
if (!stored) return null;
|
|
362
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
363
|
+
if (stored.expires_at && stored.expires_at < now + 60) {
|
|
364
|
+
return refreshSession();
|
|
365
|
+
}
|
|
366
|
+
return stored;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// src/lib/api.ts
|
|
370
|
+
var DEFAULT_API_URL = "https://provechain.aramantos.dev";
|
|
371
|
+
function getApiUrl() {
|
|
372
|
+
return process.env.PROVECHAIN_API_URL || DEFAULT_API_URL;
|
|
373
|
+
}
|
|
374
|
+
async function syncProof(proof) {
|
|
375
|
+
const session = await getValidSession();
|
|
376
|
+
if (!session) {
|
|
377
|
+
return { success: false, error: 'Not logged in. Run "provechain login" first.' };
|
|
378
|
+
}
|
|
379
|
+
const apiUrl = getApiUrl();
|
|
380
|
+
const proofJson = {
|
|
381
|
+
file_hashes: proof.file_hashes,
|
|
382
|
+
files: proof.files,
|
|
383
|
+
files_processed: proof.files_processed,
|
|
384
|
+
files_skipped: proof.files_skipped,
|
|
385
|
+
total_files: proof.total_files
|
|
386
|
+
};
|
|
387
|
+
const body = {
|
|
388
|
+
file_name: `cli-snapshot-${proof.timestamp}`,
|
|
389
|
+
file_hash: proof.proof_id,
|
|
390
|
+
timestamp: proof.timestamp,
|
|
391
|
+
proof_json: proofJson,
|
|
392
|
+
file_size: JSON.stringify(proofJson).length,
|
|
393
|
+
proof_name: proof.description || `CLI Snapshot`,
|
|
394
|
+
description: proof.description || null,
|
|
395
|
+
hash_version: proof.hash_version || 1
|
|
396
|
+
};
|
|
397
|
+
const res = await fetch(`${apiUrl}/api/proofs/create`, {
|
|
398
|
+
method: "POST",
|
|
399
|
+
headers: {
|
|
400
|
+
"Content-Type": "application/json",
|
|
401
|
+
"Authorization": `Bearer ${session.access_token}`
|
|
402
|
+
},
|
|
403
|
+
body: JSON.stringify(body)
|
|
404
|
+
});
|
|
405
|
+
const data = await res.json();
|
|
406
|
+
if (!res.ok) {
|
|
407
|
+
return { success: false, error: data.error || `HTTP ${res.status}` };
|
|
408
|
+
}
|
|
409
|
+
return { success: true, proofId: data.proof?.id };
|
|
410
|
+
}
|
|
411
|
+
async function getCloudStatus() {
|
|
412
|
+
const session = await getValidSession();
|
|
413
|
+
if (!session) {
|
|
414
|
+
return { success: false, error: "Not logged in" };
|
|
415
|
+
}
|
|
416
|
+
const apiUrl = getApiUrl();
|
|
417
|
+
const res = await fetch(`${apiUrl}/api/subscription`, {
|
|
418
|
+
headers: {
|
|
419
|
+
"Authorization": `Bearer ${session.access_token}`
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
if (!res.ok) {
|
|
423
|
+
return {
|
|
424
|
+
success: true,
|
|
425
|
+
email: session.user.email,
|
|
426
|
+
userId: session.user.id
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
const data = await res.json();
|
|
430
|
+
return {
|
|
431
|
+
success: true,
|
|
432
|
+
email: session.user.email,
|
|
433
|
+
userId: session.user.id,
|
|
434
|
+
tier: data.tier || data.subscription?.tier
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// src/commands/snapshot.ts
|
|
439
|
+
var snapshotCommand = new Command2("snapshot").description("Create a proof snapshot of current project").argument("[description]", "Description of this snapshot").option("--sync", "Upload proof to ProveChain cloud").action(async (description, opts) => {
|
|
440
|
+
const root = opts.parent?.opts()?.projectRoot || process.cwd();
|
|
441
|
+
const json = opts.parent?.opts()?.json || false;
|
|
442
|
+
const sync = opts.sync || false;
|
|
443
|
+
const config = loadConfig(root);
|
|
444
|
+
const spinner = json ? null : ora("Hashing files...").start();
|
|
445
|
+
const { hashes, skipped } = hashFiles(root, config, (current, _total, path) => {
|
|
446
|
+
if (spinner) spinner.text = `Hashing files... ${current} (${path.split("/").pop()})`;
|
|
447
|
+
});
|
|
448
|
+
if (spinner) spinner.succeed(`Hashed ${hashes.length} files (${skipped} skipped)`);
|
|
449
|
+
const proof = createProof(root, hashes, skipped, description || null);
|
|
450
|
+
const filePath = saveProof(root, proof);
|
|
451
|
+
logEvent(root, "snapshot_created", description || "Snapshot created", {
|
|
452
|
+
proof_id: proof.proof_id,
|
|
453
|
+
total_files: proof.files_processed
|
|
454
|
+
});
|
|
455
|
+
let syncResult = null;
|
|
456
|
+
if (sync) {
|
|
457
|
+
const syncSpinner = json ? null : ora("Syncing to cloud...").start();
|
|
458
|
+
try {
|
|
459
|
+
syncResult = await syncProof(proof);
|
|
460
|
+
if (syncResult.success) {
|
|
461
|
+
if (syncSpinner) syncSpinner.succeed("Synced to ProveChain cloud");
|
|
462
|
+
} else {
|
|
463
|
+
if (syncSpinner) syncSpinner.fail(`Sync failed: ${syncResult.error}`);
|
|
464
|
+
}
|
|
465
|
+
} catch (err) {
|
|
466
|
+
syncResult = { success: false, error: err.message };
|
|
467
|
+
if (syncSpinner) syncSpinner.fail(`Sync failed: ${err.message}`);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if (json) {
|
|
471
|
+
console.log(JSON.stringify({
|
|
472
|
+
success: true,
|
|
473
|
+
proof_id: proof.proof_id,
|
|
474
|
+
timestamp: proof.timestamp,
|
|
475
|
+
description: proof.description,
|
|
476
|
+
files_hashed: proof.files_processed,
|
|
477
|
+
files_skipped: proof.files_skipped,
|
|
478
|
+
total_files: proof.total_files,
|
|
479
|
+
proof_file: filePath,
|
|
480
|
+
...sync ? { sync: syncResult } : {}
|
|
481
|
+
}, null, 2));
|
|
482
|
+
} else {
|
|
483
|
+
console.log();
|
|
484
|
+
console.log(chalk2.green.bold("Proof Created!"));
|
|
485
|
+
console.log(` ${chalk2.cyan("Proof ID:")} ${chalk2.dim(proof.proof_id.slice(0, 16))}...`);
|
|
486
|
+
console.log(` ${chalk2.cyan("Files:")} ${proof.files_processed} hashed, ${proof.files_skipped} skipped`);
|
|
487
|
+
console.log(` ${chalk2.cyan("Saved:")} ${filePath}`);
|
|
488
|
+
if (description) console.log(` ${chalk2.cyan("Note:")} ${description}`);
|
|
489
|
+
if (sync && syncResult?.success) {
|
|
490
|
+
console.log(` ${chalk2.cyan("Cloud:")} ${chalk2.green("Synced")} (${syncResult.proofId})`);
|
|
491
|
+
}
|
|
492
|
+
console.log();
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
// src/commands/verify.ts
|
|
497
|
+
import { Command as Command3 } from "commander";
|
|
498
|
+
import chalk3 from "chalk";
|
|
499
|
+
import ora2 from "ora";
|
|
500
|
+
var verifyCommand = new Command3("verify").description("Verify a proof file against current state").argument("<proof_file>", "Path to proof JSON file").action((proofFile, opts) => {
|
|
501
|
+
const root = opts.parent?.opts()?.projectRoot || process.cwd();
|
|
502
|
+
const json = opts.parent?.opts()?.json || false;
|
|
503
|
+
const proof = loadProof(proofFile);
|
|
504
|
+
const config = loadConfig(root);
|
|
505
|
+
const spinner = json ? null : ora2("Re-hashing files...").start();
|
|
506
|
+
const { hashes } = hashFiles(root, config);
|
|
507
|
+
if (spinner) spinner.succeed(`Re-hashed ${hashes.length} files`);
|
|
508
|
+
const currentMap = new Map(hashes.map((h) => [h.path, h.hash]));
|
|
509
|
+
const proofMap = proof.file_hashes;
|
|
510
|
+
let matches = 0;
|
|
511
|
+
let mismatches = 0;
|
|
512
|
+
let missing = 0;
|
|
513
|
+
const mismatchDetails = [];
|
|
514
|
+
const missingFiles = [];
|
|
515
|
+
for (const [path, expectedHash] of Object.entries(proofMap)) {
|
|
516
|
+
const actualHash = currentMap.get(path);
|
|
517
|
+
if (!actualHash) {
|
|
518
|
+
missing++;
|
|
519
|
+
missingFiles.push(path);
|
|
520
|
+
} else if (actualHash !== expectedHash) {
|
|
521
|
+
mismatches++;
|
|
522
|
+
mismatchDetails.push({ path, expected: expectedHash, actual: actualHash });
|
|
523
|
+
} else {
|
|
524
|
+
matches++;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
const newFiles = [];
|
|
528
|
+
for (const h of hashes) {
|
|
529
|
+
if (!(h.path in proofMap)) newFiles.push(h.path);
|
|
530
|
+
}
|
|
531
|
+
const total = Object.keys(proofMap).length;
|
|
532
|
+
const pct = total > 0 ? Math.round(matches / total * 100) : 0;
|
|
533
|
+
const passed = mismatches === 0 && missing === 0;
|
|
534
|
+
if (json) {
|
|
535
|
+
console.log(JSON.stringify({
|
|
536
|
+
success: true,
|
|
537
|
+
proof_id: proof.proof_id,
|
|
538
|
+
timestamp: proof.timestamp,
|
|
539
|
+
verification_passed: passed,
|
|
540
|
+
matches,
|
|
541
|
+
mismatches,
|
|
542
|
+
missing,
|
|
543
|
+
new_files: newFiles.length,
|
|
544
|
+
total_files: total,
|
|
545
|
+
match_percentage: pct,
|
|
546
|
+
mismatch_details: mismatchDetails,
|
|
547
|
+
missing_files: missingFiles,
|
|
548
|
+
new_file_list: newFiles
|
|
549
|
+
}, null, 2));
|
|
550
|
+
} else {
|
|
551
|
+
console.log();
|
|
552
|
+
if (passed) {
|
|
553
|
+
console.log(chalk3.green.bold("Verification PASSED"));
|
|
554
|
+
} else {
|
|
555
|
+
console.log(chalk3.red.bold("Verification FAILED"));
|
|
556
|
+
}
|
|
557
|
+
console.log(` ${chalk3.green("Matches:")} ${matches} (${pct}%)`);
|
|
558
|
+
if (mismatches > 0) console.log(` ${chalk3.red("Mismatches:")} ${mismatches}`);
|
|
559
|
+
if (missing > 0) console.log(` ${chalk3.yellow("Missing:")} ${missing}`);
|
|
560
|
+
if (newFiles.length > 0) console.log(` ${chalk3.cyan("New files:")} ${newFiles.length}`);
|
|
561
|
+
if (mismatchDetails.length > 0) {
|
|
562
|
+
console.log();
|
|
563
|
+
console.log(chalk3.red.bold("Modified files:"));
|
|
564
|
+
for (const d of mismatchDetails.slice(0, 20)) {
|
|
565
|
+
console.log(` ${chalk3.red("~")} ${d.path}`);
|
|
566
|
+
}
|
|
567
|
+
if (mismatchDetails.length > 20) console.log(chalk3.dim(` ... and ${mismatchDetails.length - 20} more`));
|
|
568
|
+
}
|
|
569
|
+
if (missingFiles.length > 0) {
|
|
570
|
+
console.log();
|
|
571
|
+
console.log(chalk3.yellow.bold("Missing files:"));
|
|
572
|
+
for (const f of missingFiles.slice(0, 20)) {
|
|
573
|
+
console.log(` ${chalk3.yellow("?")} ${f}`);
|
|
574
|
+
}
|
|
575
|
+
if (missingFiles.length > 20) console.log(chalk3.dim(` ... and ${missingFiles.length - 20} more`));
|
|
576
|
+
}
|
|
577
|
+
console.log();
|
|
578
|
+
}
|
|
579
|
+
process.exit(passed ? 0 : 1);
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
// src/commands/list.ts
|
|
583
|
+
import { Command as Command4 } from "commander";
|
|
584
|
+
import chalk4 from "chalk";
|
|
585
|
+
import Table from "cli-table3";
|
|
586
|
+
var listCommand = new Command4("list").description("List all proof files").action((opts) => {
|
|
587
|
+
const root = opts.parent?.opts()?.projectRoot || process.cwd();
|
|
588
|
+
const json = opts.parent?.opts()?.json || false;
|
|
589
|
+
const proofs = listProofs(root);
|
|
590
|
+
if (json) {
|
|
591
|
+
console.log(JSON.stringify({
|
|
592
|
+
success: true,
|
|
593
|
+
total_proofs: proofs.length,
|
|
594
|
+
proofs: proofs.map((p) => ({
|
|
595
|
+
proof_id: p.proof.proof_id,
|
|
596
|
+
timestamp: p.proof.timestamp,
|
|
597
|
+
description: p.proof.description,
|
|
598
|
+
total_files: p.proof.files_processed,
|
|
599
|
+
file: p.file
|
|
600
|
+
}))
|
|
601
|
+
}, null, 2));
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
if (proofs.length === 0) {
|
|
605
|
+
console.log();
|
|
606
|
+
console.log(chalk4.yellow("No proofs found"));
|
|
607
|
+
console.log(chalk4.dim("Run 'provechain snapshot' to create your first proof"));
|
|
608
|
+
console.log();
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
const table = new Table({
|
|
612
|
+
head: ["#", "Date", "Description", "Files", "Proof ID"].map((h) => chalk4.cyan(h))
|
|
613
|
+
});
|
|
614
|
+
proofs.forEach((p, i) => {
|
|
615
|
+
table.push([
|
|
616
|
+
String(i + 1),
|
|
617
|
+
p.proof.timestamp.slice(0, 10),
|
|
618
|
+
(p.proof.description || chalk4.dim("(none)")).slice(0, 40),
|
|
619
|
+
String(p.proof.files_processed),
|
|
620
|
+
p.proof.proof_id.slice(0, 12) + "..."
|
|
621
|
+
]);
|
|
622
|
+
});
|
|
623
|
+
console.log();
|
|
624
|
+
console.log(chalk4.bold(`Proofs (${proofs.length} total)`));
|
|
625
|
+
console.log(table.toString());
|
|
626
|
+
console.log();
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
// src/commands/diff.ts
|
|
630
|
+
import { Command as Command5 } from "commander";
|
|
631
|
+
import chalk5 from "chalk";
|
|
632
|
+
var diffCommand = new Command5("diff").description("Compare two proof files").argument("<proof1>", "Path to first proof file").argument("<proof2>", "Path to second proof file").action((proof1Path, proof2Path, opts) => {
|
|
633
|
+
const json = opts.parent?.opts()?.json || false;
|
|
634
|
+
const p1 = loadProof(proof1Path);
|
|
635
|
+
const p2 = loadProof(proof2Path);
|
|
636
|
+
const files1 = p1.file_hashes;
|
|
637
|
+
const files2 = p2.file_hashes;
|
|
638
|
+
const allFiles = /* @__PURE__ */ new Set([...Object.keys(files1), ...Object.keys(files2)]);
|
|
639
|
+
const added = [];
|
|
640
|
+
const removed = [];
|
|
641
|
+
const modified = [];
|
|
642
|
+
let unchanged = 0;
|
|
643
|
+
for (const file of [...allFiles].sort()) {
|
|
644
|
+
if (!(file in files1)) added.push(file);
|
|
645
|
+
else if (!(file in files2)) removed.push(file);
|
|
646
|
+
else if (files1[file] !== files2[file]) modified.push(file);
|
|
647
|
+
else unchanged++;
|
|
648
|
+
}
|
|
649
|
+
if (json) {
|
|
650
|
+
console.log(JSON.stringify({
|
|
651
|
+
success: true,
|
|
652
|
+
proof1: { id: p1.proof_id, timestamp: p1.timestamp, description: p1.description, files: Object.keys(files1).length },
|
|
653
|
+
proof2: { id: p2.proof_id, timestamp: p2.timestamp, description: p2.description, files: Object.keys(files2).length },
|
|
654
|
+
differences: { added, removed, modified, unchanged_count: unchanged },
|
|
655
|
+
has_differences: added.length > 0 || removed.length > 0 || modified.length > 0
|
|
656
|
+
}, null, 2));
|
|
657
|
+
} else {
|
|
658
|
+
console.log();
|
|
659
|
+
console.log(chalk5.cyan.bold("Comparing Proofs"));
|
|
660
|
+
console.log(` ${chalk5.dim("Proof 1:")} ${p1.description || "Unnamed"} (${p1.timestamp.slice(0, 10)})`);
|
|
661
|
+
console.log(` ${chalk5.dim("Proof 2:")} ${p2.description || "Unnamed"} (${p2.timestamp.slice(0, 10)})`);
|
|
662
|
+
console.log();
|
|
663
|
+
console.log(` ${chalk5.green("Added:")} ${added.length} ${chalk5.red("Removed:")} ${removed.length} ${chalk5.yellow("Modified:")} ${modified.length} ${chalk5.dim("Unchanged:")} ${unchanged}`);
|
|
664
|
+
if (added.length > 0) {
|
|
665
|
+
console.log();
|
|
666
|
+
console.log(chalk5.green.bold("Added:"));
|
|
667
|
+
for (const f of added.slice(0, 20)) console.log(` ${chalk5.green("+")} ${f}`);
|
|
668
|
+
if (added.length > 20) console.log(chalk5.dim(` ... and ${added.length - 20} more`));
|
|
669
|
+
}
|
|
670
|
+
if (removed.length > 0) {
|
|
671
|
+
console.log();
|
|
672
|
+
console.log(chalk5.red.bold("Removed:"));
|
|
673
|
+
for (const f of removed.slice(0, 20)) console.log(` ${chalk5.red("-")} ${f}`);
|
|
674
|
+
if (removed.length > 20) console.log(chalk5.dim(` ... and ${removed.length - 20} more`));
|
|
675
|
+
}
|
|
676
|
+
if (modified.length > 0) {
|
|
677
|
+
console.log();
|
|
678
|
+
console.log(chalk5.yellow.bold("Modified:"));
|
|
679
|
+
for (const f of modified.slice(0, 20)) console.log(` ${chalk5.yellow("~")} ${f}`);
|
|
680
|
+
if (modified.length > 20) console.log(chalk5.dim(` ... and ${modified.length - 20} more`));
|
|
681
|
+
}
|
|
682
|
+
if (!added.length && !removed.length && !modified.length) {
|
|
683
|
+
console.log();
|
|
684
|
+
console.log(chalk5.green.bold("No differences found"));
|
|
685
|
+
}
|
|
686
|
+
console.log();
|
|
687
|
+
}
|
|
688
|
+
process.exit(added.length || removed.length || modified.length ? 1 : 0);
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
// src/commands/log.ts
|
|
692
|
+
import { Command as Command6 } from "commander";
|
|
693
|
+
import chalk6 from "chalk";
|
|
694
|
+
var logCommand = new Command6("log").description("Log an innovation event").argument("<description>", "Description of the innovation").action((description, opts) => {
|
|
695
|
+
const root = opts.parent?.opts()?.projectRoot || process.cwd();
|
|
696
|
+
const json = opts.parent?.opts()?.json || false;
|
|
697
|
+
logEvent(root, "innovation", description);
|
|
698
|
+
if (json) {
|
|
699
|
+
console.log(JSON.stringify({ success: true, event_type: "innovation", description }));
|
|
700
|
+
} else {
|
|
701
|
+
console.log();
|
|
702
|
+
console.log(chalk6.green.bold("Innovation logged!"));
|
|
703
|
+
console.log(` ${chalk6.dim(description)}`);
|
|
704
|
+
console.log();
|
|
705
|
+
}
|
|
706
|
+
});
|
|
707
|
+
|
|
708
|
+
// src/commands/login.ts
|
|
709
|
+
import { Command as Command7 } from "commander";
|
|
710
|
+
import chalk7 from "chalk";
|
|
711
|
+
import { createInterface } from "readline";
|
|
712
|
+
function prompt(question, hidden = false) {
|
|
713
|
+
return new Promise((resolve) => {
|
|
714
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
715
|
+
if (hidden && process.stdin.isTTY) {
|
|
716
|
+
process.stdout.write(question);
|
|
717
|
+
const stdin = process.stdin;
|
|
718
|
+
stdin.setRawMode?.(true);
|
|
719
|
+
stdin.resume();
|
|
720
|
+
let input = "";
|
|
721
|
+
const onData = (ch) => {
|
|
722
|
+
const c = ch.toString();
|
|
723
|
+
if (c === "\n" || c === "\r") {
|
|
724
|
+
stdin.setRawMode?.(false);
|
|
725
|
+
stdin.removeListener("data", onData);
|
|
726
|
+
process.stdout.write("\n");
|
|
727
|
+
rl.close();
|
|
728
|
+
resolve(input);
|
|
729
|
+
} else if (c === "") {
|
|
730
|
+
process.exit(130);
|
|
731
|
+
} else if (c === "\x7F" || c === "\b") {
|
|
732
|
+
input = input.slice(0, -1);
|
|
733
|
+
} else {
|
|
734
|
+
input += c;
|
|
735
|
+
}
|
|
736
|
+
};
|
|
737
|
+
stdin.on("data", onData);
|
|
738
|
+
} else {
|
|
739
|
+
rl.question(question, (answer) => {
|
|
740
|
+
rl.close();
|
|
741
|
+
resolve(answer);
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
var loginCommand = new Command7("login").description("Login to ProveChain cloud").action(async (opts) => {
|
|
747
|
+
const json = opts.parent?.opts()?.json || false;
|
|
748
|
+
const existing = getStoredSession();
|
|
749
|
+
if (existing) {
|
|
750
|
+
if (!json) {
|
|
751
|
+
console.log(chalk7.yellow(`Already logged in as ${existing.user.email}`));
|
|
752
|
+
console.log(chalk7.dim("Run 'provechain logout' first to switch accounts"));
|
|
753
|
+
} else {
|
|
754
|
+
console.log(JSON.stringify({ success: true, already_logged_in: true, email: existing.user.email }));
|
|
755
|
+
}
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
if (!json) {
|
|
759
|
+
console.log();
|
|
760
|
+
console.log(chalk7.cyan.bold("ProveChain Cloud Login"));
|
|
761
|
+
console.log();
|
|
762
|
+
}
|
|
763
|
+
const email = await prompt("Email: ");
|
|
764
|
+
const password = await prompt("Password: ", true);
|
|
765
|
+
try {
|
|
766
|
+
const session = await login(email, password);
|
|
767
|
+
if (json) {
|
|
768
|
+
console.log(JSON.stringify({ success: true, email: session.user.email, user_id: session.user.id }));
|
|
769
|
+
} else {
|
|
770
|
+
console.log();
|
|
771
|
+
console.log(chalk7.green.bold("Logged in successfully!"));
|
|
772
|
+
console.log(` ${chalk7.dim("Email:")} ${session.user.email}`);
|
|
773
|
+
console.log();
|
|
774
|
+
}
|
|
775
|
+
} catch (err) {
|
|
776
|
+
if (json) {
|
|
777
|
+
console.log(JSON.stringify({ success: false, error: err.message }));
|
|
778
|
+
} else {
|
|
779
|
+
console.log(chalk7.red(`Login failed: ${err.message}`));
|
|
780
|
+
}
|
|
781
|
+
process.exit(1);
|
|
782
|
+
}
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
// src/commands/logout.ts
|
|
786
|
+
import { Command as Command8 } from "commander";
|
|
787
|
+
import chalk8 from "chalk";
|
|
788
|
+
var logoutCommand = new Command8("logout").description("Logout from ProveChain cloud").action((opts) => {
|
|
789
|
+
const json = opts.parent?.opts()?.json || false;
|
|
790
|
+
const session = getStoredSession();
|
|
791
|
+
logout();
|
|
792
|
+
if (json) {
|
|
793
|
+
console.log(JSON.stringify({ success: true }));
|
|
794
|
+
} else {
|
|
795
|
+
if (session) {
|
|
796
|
+
console.log(chalk8.green(`Logged out from ${session.user.email}`));
|
|
797
|
+
} else {
|
|
798
|
+
console.log(chalk8.yellow("Not logged in"));
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
});
|
|
802
|
+
|
|
803
|
+
// src/commands/whoami.ts
|
|
804
|
+
import { Command as Command9 } from "commander";
|
|
805
|
+
import chalk9 from "chalk";
|
|
806
|
+
var whoamiCommand = new Command9("whoami").description("Show current login status").action(async (opts) => {
|
|
807
|
+
const json = opts.parent?.opts()?.json || false;
|
|
808
|
+
const session = getStoredSession();
|
|
809
|
+
if (!session) {
|
|
810
|
+
if (json) {
|
|
811
|
+
console.log(JSON.stringify({ logged_in: false }));
|
|
812
|
+
} else {
|
|
813
|
+
console.log(chalk9.yellow('Not logged in. Run "provechain login" to authenticate.'));
|
|
814
|
+
}
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
const status = await getCloudStatus();
|
|
818
|
+
if (json) {
|
|
819
|
+
console.log(JSON.stringify({
|
|
820
|
+
logged_in: true,
|
|
821
|
+
email: session.user.email,
|
|
822
|
+
user_id: session.user.id,
|
|
823
|
+
tier: status.tier || null
|
|
824
|
+
}, null, 2));
|
|
825
|
+
} else {
|
|
826
|
+
console.log();
|
|
827
|
+
console.log(chalk9.cyan.bold("ProveChain Account"));
|
|
828
|
+
console.log(` ${chalk9.dim("Email:")} ${session.user.email}`);
|
|
829
|
+
console.log(` ${chalk9.dim("User:")} ${session.user.id}`);
|
|
830
|
+
if (status.tier) {
|
|
831
|
+
console.log(` ${chalk9.dim("Plan:")} ${status.tier}`);
|
|
832
|
+
}
|
|
833
|
+
console.log();
|
|
834
|
+
}
|
|
835
|
+
});
|
|
836
|
+
|
|
837
|
+
// src/index.ts
|
|
838
|
+
var program = new Command10();
|
|
839
|
+
program.name("provechain").description("ProveChain - Cryptographic proof of existence for your files").version("1.0.0").option("--json", "Output results in JSON format").option("--project-root <path>", "Project root directory (default: cwd)");
|
|
840
|
+
program.addCommand(initCommand);
|
|
841
|
+
program.addCommand(snapshotCommand);
|
|
842
|
+
program.addCommand(verifyCommand);
|
|
843
|
+
program.addCommand(listCommand);
|
|
844
|
+
program.addCommand(diffCommand);
|
|
845
|
+
program.addCommand(logCommand);
|
|
846
|
+
program.addCommand(loginCommand);
|
|
847
|
+
program.addCommand(logoutCommand);
|
|
848
|
+
program.addCommand(whoamiCommand);
|
|
849
|
+
program.parse();
|
|
850
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/init.ts","../src/lib/config.ts","../src/commands/snapshot.ts","../src/lib/hasher.ts","../src/lib/proof.ts","../src/lib/auth.ts","../src/lib/api.ts","../src/commands/verify.ts","../src/commands/list.ts","../src/commands/diff.ts","../src/commands/log.ts","../src/commands/login.ts","../src/commands/logout.ts","../src/commands/whoami.ts"],"sourcesContent":["import { Command } from 'commander'\r\nimport { initCommand } from './commands/init.js'\r\nimport { snapshotCommand } from './commands/snapshot.js'\r\nimport { verifyCommand } from './commands/verify.js'\r\nimport { listCommand } from './commands/list.js'\r\nimport { diffCommand } from './commands/diff.js'\r\nimport { logCommand } from './commands/log.js'\r\nimport { loginCommand } from './commands/login.js'\r\nimport { logoutCommand } from './commands/logout.js'\r\nimport { whoamiCommand } from './commands/whoami.js'\r\n\r\nconst program = new Command()\r\n\r\nprogram\r\n .name('provechain')\r\n .description('ProveChain - Cryptographic proof of existence for your files')\r\n .version('1.0.0')\r\n .option('--json', 'Output results in JSON format')\r\n .option('--project-root <path>', 'Project root directory (default: cwd)')\r\n\r\nprogram.addCommand(initCommand)\r\nprogram.addCommand(snapshotCommand)\r\nprogram.addCommand(verifyCommand)\r\nprogram.addCommand(listCommand)\r\nprogram.addCommand(diffCommand)\r\nprogram.addCommand(logCommand)\r\nprogram.addCommand(loginCommand)\r\nprogram.addCommand(logoutCommand)\r\nprogram.addCommand(whoamiCommand)\r\n\r\nprogram.parse()\r\n","import { Command } from 'commander'\r\nimport chalk from 'chalk'\r\nimport { createDefaultConfig } from '../lib/config.js'\r\n\r\nexport const initCommand = new Command('init')\r\n .description('Initialize ProveChain in current project')\r\n .option('--force', 'Overwrite existing config')\r\n .action((opts) => {\r\n const root = opts.parent?.opts()?.projectRoot || process.cwd()\r\n const json = opts.parent?.opts()?.json || false\r\n\r\n const created = createDefaultConfig(root, opts.force || false)\r\n\r\n if (!created) {\r\n if (json) {\r\n console.log(JSON.stringify({ success: false, error: 'provechain.yaml already exists. Use --force to overwrite.' }))\r\n } else {\r\n console.log(chalk.red('provechain.yaml already exists.') + ' Use --force to overwrite.')\r\n }\r\n process.exit(1)\r\n }\r\n\r\n if (json) {\r\n console.log(JSON.stringify({ success: true, message: 'ProveChain initialized' }))\r\n } else {\r\n console.log()\r\n console.log(chalk.green.bold('ProveChain Initialized!'))\r\n console.log(chalk.dim(`Config: provechain.yaml`))\r\n console.log()\r\n console.log(chalk.cyan.bold('Next steps:'))\r\n console.log(` ${chalk.cyan('1.')} Edit provechain.yaml to customize settings`)\r\n console.log(` ${chalk.cyan('2.')} Run: ${chalk.green('provechain snapshot \"Initial commit\"')}`)\r\n console.log(` ${chalk.cyan('3.')} Add ${chalk.yellow('provechain/')} to your .gitignore`)\r\n console.log()\r\n }\r\n })\r\n","import { readFileSync, writeFileSync, existsSync } from 'fs'\r\nimport { join } from 'path'\r\nimport { parse } from 'yaml'\r\nimport type { ProveChainConfig } from './types.js'\r\n\r\nconst DEFAULT_CONFIG = `# ProveChain Configuration\r\n# https://provechain.aramantos.dev\r\n\r\n# File extensions to include in snapshots\r\ninclude_extensions:\r\n - .py\r\n - .js\r\n - .ts\r\n - .tsx\r\n - .jsx\r\n - .java\r\n - .go\r\n - .rs\r\n - .c\r\n - .cpp\r\n - .h\r\n - .cs\r\n - .rb\r\n - .php\r\n - .swift\r\n - .kt\r\n - .md\r\n - .yaml\r\n - .yml\r\n - .json\r\n - .toml\r\n - .sql\r\n - .sh\r\n - .css\r\n - .html\r\n - .svg\r\n\r\n# Paths to ignore (relative to project root)\r\nignore_paths:\r\n - .git\r\n - .venv\r\n - venv\r\n - node_modules\r\n - __pycache__\r\n - dist\r\n - build\r\n - .next\r\n - target\r\n - provechain\r\n - .provechain\r\n`\r\n\r\nconst DEFAULT_EXTENSIONS = [\r\n '.py', '.js', '.ts', '.tsx', '.jsx', '.java', '.go', '.rs', '.c', '.cpp',\r\n '.h', '.cs', '.rb', '.php', '.swift', '.kt', '.md', '.yaml', '.yml',\r\n '.json', '.toml', '.sql', '.sh', '.css', '.html', '.svg',\r\n]\r\n\r\nconst DEFAULT_IGNORE = [\r\n '.git', '.venv', 'venv', 'node_modules', '__pycache__', 'dist', 'build',\r\n '.next', 'target', 'provechain', '.provechain',\r\n]\r\n\r\nexport function loadConfig(projectRoot: string): ProveChainConfig {\r\n const configPath = join(projectRoot, 'provechain.yaml')\r\n\r\n if (!existsSync(configPath)) {\r\n return {\r\n include_extensions: DEFAULT_EXTENSIONS,\r\n ignore_paths: DEFAULT_IGNORE,\r\n }\r\n }\r\n\r\n const raw = readFileSync(configPath, 'utf-8')\r\n const parsed = parse(raw) as Partial<ProveChainConfig>\r\n\r\n return {\r\n include_extensions: parsed.include_extensions || DEFAULT_EXTENSIONS,\r\n ignore_paths: parsed.ignore_paths || DEFAULT_IGNORE,\r\n }\r\n}\r\n\r\nexport function createDefaultConfig(projectRoot: string, force: boolean): boolean {\r\n const configPath = join(projectRoot, 'provechain.yaml')\r\n\r\n if (existsSync(configPath) && !force) {\r\n return false\r\n }\r\n\r\n writeFileSync(configPath, DEFAULT_CONFIG, 'utf-8')\r\n return true\r\n}\r\n","import { Command } from 'commander'\r\nimport chalk from 'chalk'\r\nimport ora from 'ora'\r\nimport { loadConfig } from '../lib/config.js'\r\nimport { hashFiles } from '../lib/hasher.js'\r\nimport { createProof, saveProof, logEvent } from '../lib/proof.js'\r\nimport { syncProof } from '../lib/api.js'\r\n\r\nexport const snapshotCommand = new Command('snapshot')\r\n .description('Create a proof snapshot of current project')\r\n .argument('[description]', 'Description of this snapshot')\r\n .option('--sync', 'Upload proof to ProveChain cloud')\r\n .action(async (description, opts) => {\r\n const root = opts.parent?.opts()?.projectRoot || process.cwd()\r\n const json = opts.parent?.opts()?.json || false\r\n const sync = opts.sync || false\r\n\r\n const config = loadConfig(root)\r\n\r\n const spinner = json ? null : ora('Hashing files...').start()\r\n\r\n const { hashes, skipped } = hashFiles(root, config, (current, _total, path) => {\r\n if (spinner) spinner.text = `Hashing files... ${current} (${path.split('/').pop()})`\r\n })\r\n\r\n if (spinner) spinner.succeed(`Hashed ${hashes.length} files (${skipped} skipped)`)\r\n\r\n const proof = createProof(root, hashes, skipped, description || null)\r\n const filePath = saveProof(root, proof)\r\n\r\n // Log to ledger\r\n logEvent(root, 'snapshot_created', description || 'Snapshot created', {\r\n proof_id: proof.proof_id,\r\n total_files: proof.files_processed,\r\n })\r\n\r\n // Cloud sync\r\n let syncResult: { success: boolean; proofId?: string; error?: string } | null = null\r\n if (sync) {\r\n const syncSpinner = json ? null : ora('Syncing to cloud...').start()\r\n try {\r\n syncResult = await syncProof(proof)\r\n if (syncResult.success) {\r\n if (syncSpinner) syncSpinner.succeed('Synced to ProveChain cloud')\r\n } else {\r\n if (syncSpinner) syncSpinner.fail(`Sync failed: ${syncResult.error}`)\r\n }\r\n } catch (err: any) {\r\n syncResult = { success: false, error: err.message }\r\n if (syncSpinner) syncSpinner.fail(`Sync failed: ${err.message}`)\r\n }\r\n }\r\n\r\n if (json) {\r\n console.log(JSON.stringify({\r\n success: true,\r\n proof_id: proof.proof_id,\r\n timestamp: proof.timestamp,\r\n description: proof.description,\r\n files_hashed: proof.files_processed,\r\n files_skipped: proof.files_skipped,\r\n total_files: proof.total_files,\r\n proof_file: filePath,\r\n ...(sync ? { sync: syncResult } : {}),\r\n }, null, 2))\r\n } else {\r\n console.log()\r\n console.log(chalk.green.bold('Proof Created!'))\r\n console.log(` ${chalk.cyan('Proof ID:')} ${chalk.dim(proof.proof_id.slice(0, 16))}...`)\r\n console.log(` ${chalk.cyan('Files:')} ${proof.files_processed} hashed, ${proof.files_skipped} skipped`)\r\n console.log(` ${chalk.cyan('Saved:')} ${filePath}`)\r\n if (description) console.log(` ${chalk.cyan('Note:')} ${description}`)\r\n if (sync && syncResult?.success) {\r\n console.log(` ${chalk.cyan('Cloud:')} ${chalk.green('Synced')} (${syncResult.proofId})`)\r\n }\r\n console.log()\r\n }\r\n })\r\n","import { createHash } from 'crypto'\r\nimport { readFileSync, readdirSync, statSync } from 'fs'\r\nimport { join, relative, extname } from 'path'\r\nimport type { FileHash, ProveChainConfig } from './types.js'\r\n\r\n/**\r\n * Compute SHA-256 hash of a file\r\n */\r\nexport function hashFile(filePath: string): string {\r\n const buffer = readFileSync(filePath)\r\n return createHash('sha256').update(buffer).digest('hex')\r\n}\r\n\r\n/**\r\n * Walk directory and hash all matching files\r\n */\r\nexport function hashFiles(\r\n projectRoot: string,\r\n config: ProveChainConfig,\r\n onProgress?: (current: number, total: number, path: string) => void\r\n): { hashes: FileHash[]; skipped: number } {\r\n const hashes: FileHash[] = []\r\n let skipped = 0\r\n\r\n const extensionSet = new Set(config.include_extensions)\r\n const ignoreSet = new Set(config.ignore_paths)\r\n\r\n function walk(dir: string) {\r\n let entries: string[]\r\n try {\r\n entries = readdirSync(dir)\r\n } catch {\r\n return\r\n }\r\n\r\n for (const entry of entries) {\r\n // Skip ignored paths\r\n const relPath = relative(projectRoot, join(dir, entry))\r\n const topLevel = relPath.split(/[/\\\\]/)[0]\r\n if (ignoreSet.has(topLevel) || ignoreSet.has(entry)) {\r\n continue\r\n }\r\n\r\n // Skip hidden files/folders\r\n if (entry.startsWith('.')) {\r\n continue\r\n }\r\n\r\n const fullPath = join(dir, entry)\r\n let stat\r\n try {\r\n stat = statSync(fullPath)\r\n } catch {\r\n skipped++\r\n continue\r\n }\r\n\r\n if (stat.isDirectory()) {\r\n walk(fullPath)\r\n } else if (stat.isFile()) {\r\n const ext = extname(entry).toLowerCase()\r\n if (!extensionSet.has(ext)) {\r\n skipped++\r\n continue\r\n }\r\n\r\n try {\r\n const hash = hashFile(fullPath)\r\n // Normalize path to forward slashes\r\n const normalizedPath = relative(projectRoot, fullPath).replace(/\\\\/g, '/')\r\n\r\n hashes.push({\r\n path: normalizedPath,\r\n hash,\r\n size: stat.size,\r\n })\r\n\r\n if (onProgress) {\r\n onProgress(hashes.length, 0, normalizedPath)\r\n }\r\n } catch {\r\n skipped++\r\n }\r\n }\r\n }\r\n }\r\n\r\n walk(projectRoot)\r\n\r\n // Sort by path using byte-order for cross-platform determinism\r\n // Canonical algorithm matching @aramantos/crypto Rust lib\r\n hashes.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0)\r\n\r\n return { hashes, skipped }\r\n}\r\n\r\n/**\r\n * Generate deterministic proof hash from file hashes.\r\n * Canonical algorithm (matches @aramantos/crypto Rust lib):\r\n * 1. SHA-256 each file individually\r\n * 2. Create entries as path:hash\r\n * 3. Sort alphabetically (byte-order)\r\n * 4. Join with newlines\r\n * 5. SHA-256 the result\r\n */\r\nexport function generateProofHash(fileHashes: FileHash[]): string {\r\n const sorted = [...fileHashes].sort((a, b) =>\r\n a.path < b.path ? -1 : a.path > b.path ? 1 : 0\r\n )\r\n\r\n const manifest = sorted\r\n .map(f => `${f.path}:${f.hash}`)\r\n .join('\\n')\r\n\r\n return createHash('sha256').update(manifest).digest('hex')\r\n}\r\n","import { readFileSync, writeFileSync, appendFileSync, mkdirSync, readdirSync, existsSync } from 'fs'\r\nimport { join } from 'path'\r\nimport { randomUUID } from 'crypto'\r\nimport type { FileHash, ProofData } from './types.js'\r\nimport { generateProofHash } from './hasher.js'\r\n\r\nconst PROOFS_DIR = 'provechain/proofs'\r\nconst LEDGER_FILE = 'provechain/innovation_ledger.ndjson'\r\n\r\nexport function ensureProofsDir(projectRoot: string): string {\r\n const dir = join(projectRoot, PROOFS_DIR)\r\n mkdirSync(dir, { recursive: true })\r\n return dir\r\n}\r\n\r\nexport function createProof(\r\n projectRoot: string,\r\n fileHashes: FileHash[],\r\n skipped: number,\r\n description: string | null\r\n): ProofData {\r\n const proofId = generateProofHash(fileHashes)\r\n const fileHashMap: Record<string, string> = {}\r\n\r\n for (const fh of fileHashes) {\r\n fileHashMap[fh.path] = fh.hash\r\n }\r\n\r\n return {\r\n proof_id: proofId,\r\n timestamp: new Date().toISOString(),\r\n description,\r\n project_root: projectRoot,\r\n total_files: fileHashes.length + skipped,\r\n files_processed: fileHashes.length,\r\n files_skipped: skipped,\r\n file_hashes: fileHashMap,\r\n files: fileHashes,\r\n hash_version: 1,\r\n }\r\n}\r\n\r\nexport function saveProof(projectRoot: string, proof: ProofData): string {\r\n const dir = ensureProofsDir(projectRoot)\r\n const dateStr = proof.timestamp.replace(/:/g, '-').replace(/\\./g, '-')\r\n const filename = `proof_${dateStr}.json`\r\n const filePath = join(dir, filename)\r\n\r\n writeFileSync(filePath, JSON.stringify(proof, null, 2), 'utf-8')\r\n return filePath\r\n}\r\n\r\nexport function loadProof(filePath: string): ProofData {\r\n const raw = readFileSync(filePath, 'utf-8')\r\n return JSON.parse(raw) as ProofData\r\n}\r\n\r\nexport function listProofs(projectRoot: string): { proof: ProofData; file: string }[] {\r\n const dir = join(projectRoot, PROOFS_DIR)\r\n\r\n if (!existsSync(dir)) return []\r\n\r\n const files = readdirSync(dir)\r\n .filter(f => f.startsWith('proof_') && f.endsWith('.json'))\r\n .sort()\r\n .reverse()\r\n\r\n return files.map(file => ({\r\n proof: loadProof(join(dir, file)),\r\n file,\r\n }))\r\n}\r\n\r\nexport function logEvent(\r\n projectRoot: string,\r\n eventType: string,\r\n description: string,\r\n metadata?: Record<string, unknown>\r\n): void {\r\n const ledgerPath = join(projectRoot, LEDGER_FILE)\r\n mkdirSync(join(projectRoot, 'provechain'), { recursive: true })\r\n\r\n const entry = {\r\n event_id: randomUUID(),\r\n timestamp: new Date().toISOString(),\r\n event_type: eventType,\r\n description,\r\n ...metadata,\r\n }\r\n\r\n const line = JSON.stringify(entry) + '\\n'\r\n\r\n appendFileSync(ledgerPath, line, 'utf-8')\r\n}\r\n","import { createClient } from '@supabase/supabase-js'\r\nimport { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync } from 'fs'\r\nimport { join } from 'path'\r\nimport { homedir } from 'os'\r\nimport type { StoredSession } from './types.js'\r\n\r\nconst CORE_SUPABASE_URL = 'https://kxhesmrmfawujrwrrres.supabase.co'\r\nconst CORE_SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Imt4aGVzbXJtZmF3dWpyd3JycmVzIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Mzc4MzIyMjUsImV4cCI6MjA1MzQwODIyNX0.2PNjBJOXJGUMiP8foWQxZKHAHVNjdlQaBe0K8skVFaY'\r\n\r\nconst CONFIG_DIR = join(homedir(), '.provechain')\r\nconst CREDENTIALS_FILE = join(CONFIG_DIR, 'credentials.json')\r\n\r\nfunction getClient() {\r\n return createClient(CORE_SUPABASE_URL, CORE_SUPABASE_ANON_KEY)\r\n}\r\n\r\nexport async function login(email: string, password: string): Promise<StoredSession> {\r\n const supabase = getClient()\r\n const { data, error } = await supabase.auth.signInWithPassword({ email, password })\r\n\r\n if (error) throw new Error(error.message)\r\n if (!data.session || !data.user) throw new Error('Login failed')\r\n\r\n const session: StoredSession = {\r\n access_token: data.session.access_token,\r\n refresh_token: data.session.refresh_token,\r\n expires_at: data.session.expires_at || 0,\r\n user: { id: data.user.id, email: data.user.email || email },\r\n }\r\n\r\n mkdirSync(CONFIG_DIR, { recursive: true })\r\n writeFileSync(CREDENTIALS_FILE, JSON.stringify(session, null, 2), { mode: 0o600 })\r\n\r\n return session\r\n}\r\n\r\nexport function logout(): void {\r\n if (existsSync(CREDENTIALS_FILE)) {\r\n unlinkSync(CREDENTIALS_FILE)\r\n }\r\n}\r\n\r\nexport function getStoredSession(): StoredSession | null {\r\n if (!existsSync(CREDENTIALS_FILE)) return null\r\n try {\r\n const raw = readFileSync(CREDENTIALS_FILE, 'utf-8')\r\n return JSON.parse(raw) as StoredSession\r\n } catch {\r\n return null\r\n }\r\n}\r\n\r\nexport async function refreshSession(): Promise<StoredSession | null> {\r\n const stored = getStoredSession()\r\n if (!stored) return null\r\n\r\n const supabase = getClient()\r\n const { data, error } = await supabase.auth.setSession({\r\n access_token: stored.access_token,\r\n refresh_token: stored.refresh_token,\r\n })\r\n\r\n if (error || !data.session) {\r\n logout()\r\n return null\r\n }\r\n\r\n const session: StoredSession = {\r\n access_token: data.session.access_token,\r\n refresh_token: data.session.refresh_token,\r\n expires_at: data.session.expires_at || 0,\r\n user: stored.user,\r\n }\r\n\r\n writeFileSync(CREDENTIALS_FILE, JSON.stringify(session, null, 2), { mode: 0o600 })\r\n return session\r\n}\r\n\r\nexport async function getValidSession(): Promise<StoredSession | null> {\r\n const stored = getStoredSession()\r\n if (!stored) return null\r\n\r\n const now = Math.floor(Date.now() / 1000)\r\n if (stored.expires_at && stored.expires_at < now + 60) {\r\n return refreshSession()\r\n }\r\n\r\n return stored\r\n}\r\n","import { getValidSession } from './auth.js'\r\nimport type { ProofData } from './types.js'\r\n\r\nconst DEFAULT_API_URL = 'https://provechain.aramantos.dev'\r\n\r\nfunction getApiUrl(): string {\r\n return process.env.PROVECHAIN_API_URL || DEFAULT_API_URL\r\n}\r\n\r\nexport async function syncProof(proof: ProofData): Promise<{\r\n success: boolean\r\n proofId?: string\r\n error?: string\r\n}> {\r\n const session = await getValidSession()\r\n if (!session) {\r\n return { success: false, error: 'Not logged in. Run \"provechain login\" first.' }\r\n }\r\n\r\n const apiUrl = getApiUrl()\r\n const proofJson = {\r\n file_hashes: proof.file_hashes,\r\n files: proof.files,\r\n files_processed: proof.files_processed,\r\n files_skipped: proof.files_skipped,\r\n total_files: proof.total_files,\r\n }\r\n\r\n const body = {\r\n file_name: `cli-snapshot-${proof.timestamp}`,\r\n file_hash: proof.proof_id,\r\n timestamp: proof.timestamp,\r\n proof_json: proofJson,\r\n file_size: JSON.stringify(proofJson).length,\r\n proof_name: proof.description || `CLI Snapshot`,\r\n description: proof.description || null,\r\n hash_version: proof.hash_version || 1,\r\n }\r\n\r\n const res = await fetch(`${apiUrl}/api/proofs/create`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Authorization': `Bearer ${session.access_token}`,\r\n },\r\n body: JSON.stringify(body),\r\n })\r\n\r\n const data = await res.json()\r\n\r\n if (!res.ok) {\r\n return { success: false, error: data.error || `HTTP ${res.status}` }\r\n }\r\n\r\n return { success: true, proofId: data.proof?.id }\r\n}\r\n\r\nexport async function getCloudStatus(): Promise<{\r\n success: boolean\r\n email?: string\r\n userId?: string\r\n tier?: string\r\n proofCount?: number\r\n error?: string\r\n}> {\r\n const session = await getValidSession()\r\n if (!session) {\r\n return { success: false, error: 'Not logged in' }\r\n }\r\n\r\n const apiUrl = getApiUrl()\r\n\r\n const res = await fetch(`${apiUrl}/api/subscription`, {\r\n headers: {\r\n 'Authorization': `Bearer ${session.access_token}`,\r\n },\r\n })\r\n\r\n if (!res.ok) {\r\n return {\r\n success: true,\r\n email: session.user.email,\r\n userId: session.user.id,\r\n }\r\n }\r\n\r\n const data = await res.json()\r\n\r\n return {\r\n success: true,\r\n email: session.user.email,\r\n userId: session.user.id,\r\n tier: data.tier || data.subscription?.tier,\r\n }\r\n}\r\n","import { Command } from 'commander'\r\nimport chalk from 'chalk'\r\nimport ora from 'ora'\r\nimport { loadConfig } from '../lib/config.js'\r\nimport { hashFiles, generateProofHash } from '../lib/hasher.js'\r\nimport { loadProof } from '../lib/proof.js'\r\n\r\nexport const verifyCommand = new Command('verify')\r\n .description('Verify a proof file against current state')\r\n .argument('<proof_file>', 'Path to proof JSON file')\r\n .action((proofFile, opts) => {\r\n const root = opts.parent?.opts()?.projectRoot || process.cwd()\r\n const json = opts.parent?.opts()?.json || false\r\n\r\n const proof = loadProof(proofFile)\r\n const config = loadConfig(root)\r\n\r\n const spinner = json ? null : ora('Re-hashing files...').start()\r\n const { hashes } = hashFiles(root, config)\r\n if (spinner) spinner.succeed(`Re-hashed ${hashes.length} files`)\r\n\r\n const currentMap = new Map(hashes.map(h => [h.path, h.hash]))\r\n const proofMap = proof.file_hashes\r\n\r\n let matches = 0\r\n let mismatches = 0\r\n let missing = 0\r\n const mismatchDetails: { path: string; expected: string; actual: string }[] = []\r\n const missingFiles: string[] = []\r\n\r\n for (const [path, expectedHash] of Object.entries(proofMap)) {\r\n const actualHash = currentMap.get(path)\r\n if (!actualHash) {\r\n missing++\r\n missingFiles.push(path)\r\n } else if (actualHash !== expectedHash) {\r\n mismatches++\r\n mismatchDetails.push({ path, expected: expectedHash, actual: actualHash })\r\n } else {\r\n matches++\r\n }\r\n }\r\n\r\n // New files not in proof\r\n const newFiles: string[] = []\r\n for (const h of hashes) {\r\n if (!(h.path in proofMap)) newFiles.push(h.path)\r\n }\r\n\r\n const total = Object.keys(proofMap).length\r\n const pct = total > 0 ? Math.round((matches / total) * 100) : 0\r\n const passed = mismatches === 0 && missing === 0\r\n\r\n if (json) {\r\n console.log(JSON.stringify({\r\n success: true,\r\n proof_id: proof.proof_id,\r\n timestamp: proof.timestamp,\r\n verification_passed: passed,\r\n matches,\r\n mismatches,\r\n missing,\r\n new_files: newFiles.length,\r\n total_files: total,\r\n match_percentage: pct,\r\n mismatch_details: mismatchDetails,\r\n missing_files: missingFiles,\r\n new_file_list: newFiles,\r\n }, null, 2))\r\n } else {\r\n console.log()\r\n if (passed) {\r\n console.log(chalk.green.bold('Verification PASSED'))\r\n } else {\r\n console.log(chalk.red.bold('Verification FAILED'))\r\n }\r\n console.log(` ${chalk.green('Matches:')} ${matches} (${pct}%)`)\r\n if (mismatches > 0) console.log(` ${chalk.red('Mismatches:')} ${mismatches}`)\r\n if (missing > 0) console.log(` ${chalk.yellow('Missing:')} ${missing}`)\r\n if (newFiles.length > 0) console.log(` ${chalk.cyan('New files:')} ${newFiles.length}`)\r\n\r\n if (mismatchDetails.length > 0) {\r\n console.log()\r\n console.log(chalk.red.bold('Modified files:'))\r\n for (const d of mismatchDetails.slice(0, 20)) {\r\n console.log(` ${chalk.red('~')} ${d.path}`)\r\n }\r\n if (mismatchDetails.length > 20) console.log(chalk.dim(` ... and ${mismatchDetails.length - 20} more`))\r\n }\r\n\r\n if (missingFiles.length > 0) {\r\n console.log()\r\n console.log(chalk.yellow.bold('Missing files:'))\r\n for (const f of missingFiles.slice(0, 20)) {\r\n console.log(` ${chalk.yellow('?')} ${f}`)\r\n }\r\n if (missingFiles.length > 20) console.log(chalk.dim(` ... and ${missingFiles.length - 20} more`))\r\n }\r\n console.log()\r\n }\r\n\r\n process.exit(passed ? 0 : 1)\r\n })\r\n","import { Command } from 'commander'\r\nimport chalk from 'chalk'\r\nimport Table from 'cli-table3'\r\nimport { listProofs } from '../lib/proof.js'\r\n\r\nexport const listCommand = new Command('list')\r\n .description('List all proof files')\r\n .action((opts) => {\r\n const root = opts.parent?.opts()?.projectRoot || process.cwd()\r\n const json = opts.parent?.opts()?.json || false\r\n\r\n const proofs = listProofs(root)\r\n\r\n if (json) {\r\n console.log(JSON.stringify({\r\n success: true,\r\n total_proofs: proofs.length,\r\n proofs: proofs.map(p => ({\r\n proof_id: p.proof.proof_id,\r\n timestamp: p.proof.timestamp,\r\n description: p.proof.description,\r\n total_files: p.proof.files_processed,\r\n file: p.file,\r\n })),\r\n }, null, 2))\r\n return\r\n }\r\n\r\n if (proofs.length === 0) {\r\n console.log()\r\n console.log(chalk.yellow('No proofs found'))\r\n console.log(chalk.dim(\"Run 'provechain snapshot' to create your first proof\"))\r\n console.log()\r\n return\r\n }\r\n\r\n const table = new Table({\r\n head: ['#', 'Date', 'Description', 'Files', 'Proof ID'].map(h => chalk.cyan(h)),\r\n })\r\n\r\n proofs.forEach((p, i) => {\r\n table.push([\r\n String(i + 1),\r\n p.proof.timestamp.slice(0, 10),\r\n (p.proof.description || chalk.dim('(none)')).slice(0, 40),\r\n String(p.proof.files_processed),\r\n p.proof.proof_id.slice(0, 12) + '...',\r\n ])\r\n })\r\n\r\n console.log()\r\n console.log(chalk.bold(`Proofs (${proofs.length} total)`))\r\n console.log(table.toString())\r\n console.log()\r\n })\r\n","import { Command } from 'commander'\r\nimport chalk from 'chalk'\r\nimport { loadProof } from '../lib/proof.js'\r\n\r\nexport const diffCommand = new Command('diff')\r\n .description('Compare two proof files')\r\n .argument('<proof1>', 'Path to first proof file')\r\n .argument('<proof2>', 'Path to second proof file')\r\n .action((proof1Path, proof2Path, opts) => {\r\n const json = opts.parent?.opts()?.json || false\r\n\r\n const p1 = loadProof(proof1Path)\r\n const p2 = loadProof(proof2Path)\r\n\r\n const files1 = p1.file_hashes\r\n const files2 = p2.file_hashes\r\n const allFiles = new Set([...Object.keys(files1), ...Object.keys(files2)])\r\n\r\n const added: string[] = []\r\n const removed: string[] = []\r\n const modified: string[] = []\r\n let unchanged = 0\r\n\r\n for (const file of [...allFiles].sort()) {\r\n if (!(file in files1)) added.push(file)\r\n else if (!(file in files2)) removed.push(file)\r\n else if (files1[file] !== files2[file]) modified.push(file)\r\n else unchanged++\r\n }\r\n\r\n if (json) {\r\n console.log(JSON.stringify({\r\n success: true,\r\n proof1: { id: p1.proof_id, timestamp: p1.timestamp, description: p1.description, files: Object.keys(files1).length },\r\n proof2: { id: p2.proof_id, timestamp: p2.timestamp, description: p2.description, files: Object.keys(files2).length },\r\n differences: { added, removed, modified, unchanged_count: unchanged },\r\n has_differences: added.length > 0 || removed.length > 0 || modified.length > 0,\r\n }, null, 2))\r\n } else {\r\n console.log()\r\n console.log(chalk.cyan.bold('Comparing Proofs'))\r\n console.log(` ${chalk.dim('Proof 1:')} ${p1.description || 'Unnamed'} (${p1.timestamp.slice(0, 10)})`)\r\n console.log(` ${chalk.dim('Proof 2:')} ${p2.description || 'Unnamed'} (${p2.timestamp.slice(0, 10)})`)\r\n console.log()\r\n console.log(` ${chalk.green('Added:')} ${added.length} ${chalk.red('Removed:')} ${removed.length} ${chalk.yellow('Modified:')} ${modified.length} ${chalk.dim('Unchanged:')} ${unchanged}`)\r\n\r\n if (added.length > 0) {\r\n console.log()\r\n console.log(chalk.green.bold('Added:'))\r\n for (const f of added.slice(0, 20)) console.log(` ${chalk.green('+')} ${f}`)\r\n if (added.length > 20) console.log(chalk.dim(` ... and ${added.length - 20} more`))\r\n }\r\n if (removed.length > 0) {\r\n console.log()\r\n console.log(chalk.red.bold('Removed:'))\r\n for (const f of removed.slice(0, 20)) console.log(` ${chalk.red('-')} ${f}`)\r\n if (removed.length > 20) console.log(chalk.dim(` ... and ${removed.length - 20} more`))\r\n }\r\n if (modified.length > 0) {\r\n console.log()\r\n console.log(chalk.yellow.bold('Modified:'))\r\n for (const f of modified.slice(0, 20)) console.log(` ${chalk.yellow('~')} ${f}`)\r\n if (modified.length > 20) console.log(chalk.dim(` ... and ${modified.length - 20} more`))\r\n }\r\n if (!added.length && !removed.length && !modified.length) {\r\n console.log()\r\n console.log(chalk.green.bold('No differences found'))\r\n }\r\n console.log()\r\n }\r\n\r\n process.exit(added.length || removed.length || modified.length ? 1 : 0)\r\n })\r\n","import { Command } from 'commander'\r\nimport chalk from 'chalk'\r\nimport { logEvent } from '../lib/proof.js'\r\n\r\nexport const logCommand = new Command('log')\r\n .description('Log an innovation event')\r\n .argument('<description>', 'Description of the innovation')\r\n .action((description, opts) => {\r\n const root = opts.parent?.opts()?.projectRoot || process.cwd()\r\n const json = opts.parent?.opts()?.json || false\r\n\r\n logEvent(root, 'innovation', description)\r\n\r\n if (json) {\r\n console.log(JSON.stringify({ success: true, event_type: 'innovation', description }))\r\n } else {\r\n console.log()\r\n console.log(chalk.green.bold('Innovation logged!'))\r\n console.log(` ${chalk.dim(description)}`)\r\n console.log()\r\n }\r\n })\r\n","import { Command } from 'commander'\r\nimport chalk from 'chalk'\r\nimport { createInterface } from 'readline'\r\nimport { login, getStoredSession, logout } from '../lib/auth.js'\r\n\r\nfunction prompt(question: string, hidden = false): Promise<string> {\r\n return new Promise((resolve) => {\r\n const rl = createInterface({ input: process.stdin, output: process.stdout })\r\n if (hidden && process.stdin.isTTY) {\r\n process.stdout.write(question)\r\n const stdin = process.stdin\r\n stdin.setRawMode?.(true)\r\n stdin.resume()\r\n let input = ''\r\n const onData = (ch: Buffer) => {\r\n const c = ch.toString()\r\n if (c === '\\n' || c === '\\r') {\r\n stdin.setRawMode?.(false)\r\n stdin.removeListener('data', onData)\r\n process.stdout.write('\\n')\r\n rl.close()\r\n resolve(input)\r\n } else if (c === '\\u0003') {\r\n process.exit(130)\r\n } else if (c === '\\u007f' || c === '\\b') {\r\n input = input.slice(0, -1)\r\n } else {\r\n input += c\r\n }\r\n }\r\n stdin.on('data', onData)\r\n } else {\r\n rl.question(question, (answer) => { rl.close(); resolve(answer) })\r\n }\r\n })\r\n}\r\n\r\nexport const loginCommand = new Command('login')\r\n .description('Login to ProveChain cloud')\r\n .action(async (opts) => {\r\n const json = opts.parent?.opts()?.json || false\r\n\r\n const existing = getStoredSession()\r\n if (existing) {\r\n if (!json) {\r\n console.log(chalk.yellow(`Already logged in as ${existing.user.email}`))\r\n console.log(chalk.dim(\"Run 'provechain logout' first to switch accounts\"))\r\n } else {\r\n console.log(JSON.stringify({ success: true, already_logged_in: true, email: existing.user.email }))\r\n }\r\n return\r\n }\r\n\r\n if (!json) {\r\n console.log()\r\n console.log(chalk.cyan.bold('ProveChain Cloud Login'))\r\n console.log()\r\n }\r\n\r\n const email = await prompt('Email: ')\r\n const password = await prompt('Password: ', true)\r\n\r\n try {\r\n const session = await login(email, password)\r\n if (json) {\r\n console.log(JSON.stringify({ success: true, email: session.user.email, user_id: session.user.id }))\r\n } else {\r\n console.log()\r\n console.log(chalk.green.bold('Logged in successfully!'))\r\n console.log(` ${chalk.dim('Email:')} ${session.user.email}`)\r\n console.log()\r\n }\r\n } catch (err: any) {\r\n if (json) {\r\n console.log(JSON.stringify({ success: false, error: err.message }))\r\n } else {\r\n console.log(chalk.red(`Login failed: ${err.message}`))\r\n }\r\n process.exit(1)\r\n }\r\n })\r\n","import { Command } from 'commander'\r\nimport chalk from 'chalk'\r\nimport { logout, getStoredSession } from '../lib/auth.js'\r\n\r\nexport const logoutCommand = new Command('logout')\r\n .description('Logout from ProveChain cloud')\r\n .action((opts) => {\r\n const json = opts.parent?.opts()?.json || false\r\n const session = getStoredSession()\r\n\r\n logout()\r\n\r\n if (json) {\r\n console.log(JSON.stringify({ success: true }))\r\n } else {\r\n if (session) {\r\n console.log(chalk.green(`Logged out from ${session.user.email}`))\r\n } else {\r\n console.log(chalk.yellow('Not logged in'))\r\n }\r\n }\r\n })\r\n","import { Command } from 'commander'\r\nimport chalk from 'chalk'\r\nimport { getStoredSession } from '../lib/auth.js'\r\nimport { getCloudStatus } from '../lib/api.js'\r\n\r\nexport const whoamiCommand = new Command('whoami')\r\n .description('Show current login status')\r\n .action(async (opts) => {\r\n const json = opts.parent?.opts()?.json || false\r\n const session = getStoredSession()\r\n\r\n if (!session) {\r\n if (json) {\r\n console.log(JSON.stringify({ logged_in: false }))\r\n } else {\r\n console.log(chalk.yellow('Not logged in. Run \"provechain login\" to authenticate.'))\r\n }\r\n return\r\n }\r\n\r\n // Try to get cloud status (tier info)\r\n const status = await getCloudStatus()\r\n\r\n if (json) {\r\n console.log(JSON.stringify({\r\n logged_in: true,\r\n email: session.user.email,\r\n user_id: session.user.id,\r\n tier: status.tier || null,\r\n }, null, 2))\r\n } else {\r\n console.log()\r\n console.log(chalk.cyan.bold('ProveChain Account'))\r\n console.log(` ${chalk.dim('Email:')} ${session.user.email}`)\r\n console.log(` ${chalk.dim('User:')} ${session.user.id}`)\r\n if (status.tier) {\r\n console.log(` ${chalk.dim('Plan:')} ${status.tier}`)\r\n }\r\n console.log()\r\n }\r\n })\r\n"],"mappings":"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","names":["Command","Command","chalk","readFileSync","join","readFileSync","writeFileSync","readdirSync","existsSync","join","join","writeFileSync","readFileSync","existsSync","readdirSync","readFileSync","writeFileSync","mkdirSync","existsSync","join","Command","chalk","Command","chalk","ora","Command","ora","chalk","Command","chalk","Command","chalk","Command","chalk","Command","chalk","Command","chalk","Command","chalk","Command","chalk","Command","chalk","Command","chalk","Command","chalk","Command","chalk","Command","chalk","Command"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aramantos/provechain-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "ProveChain CLI - Cryptographic proof of existence for your files",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"provechain": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsup",
|
|
11
|
+
"dev": "tsup --watch",
|
|
12
|
+
"start": "node dist/index.js",
|
|
13
|
+
"typecheck": "tsc --noEmit"
|
|
14
|
+
},
|
|
15
|
+
"author": "John Doyle <john@aramantos.dev>",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/Aramantos/provechain"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"blockchain",
|
|
23
|
+
"timestamp",
|
|
24
|
+
"proof",
|
|
25
|
+
"authorship",
|
|
26
|
+
"sha256",
|
|
27
|
+
"cryptography"
|
|
28
|
+
],
|
|
29
|
+
"files": [
|
|
30
|
+
"dist"
|
|
31
|
+
],
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=18.0.0"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@supabase/supabase-js": "^2.49.0",
|
|
37
|
+
"chalk": "^5.4.0",
|
|
38
|
+
"cli-table3": "^0.6.5",
|
|
39
|
+
"commander": "^13.1.0",
|
|
40
|
+
"ora": "^8.2.0",
|
|
41
|
+
"yaml": "^2.7.0"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^22.0.0",
|
|
45
|
+
"tsup": "^8.4.0",
|
|
46
|
+
"typescript": "^5.7.0"
|
|
47
|
+
}
|
|
48
|
+
}
|