ccsini 0.1.25 → 0.1.26
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 +108 -46
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -27996,7 +27996,7 @@ var {
|
|
|
27996
27996
|
} = import__.default;
|
|
27997
27997
|
|
|
27998
27998
|
// src/version.ts
|
|
27999
|
-
var VERSION = "0.1.
|
|
27999
|
+
var VERSION = "0.1.26";
|
|
28000
28000
|
|
|
28001
28001
|
// src/commands/init.ts
|
|
28002
28002
|
init_source();
|
|
@@ -29360,6 +29360,8 @@ function chunkArray(arr, size) {
|
|
|
29360
29360
|
}
|
|
29361
29361
|
|
|
29362
29362
|
// src/commands/init.ts
|
|
29363
|
+
import { writeFile as writeFile6 } from "fs/promises";
|
|
29364
|
+
import { join as join7 } from "path";
|
|
29363
29365
|
function registerInitCommand(program2) {
|
|
29364
29366
|
program2.command("init").description("Connect this device to your ccsini account").option("--token <token>", "Setup token from dashboard").action(async (opts) => {
|
|
29365
29367
|
const configDir = getConfigDir();
|
|
@@ -29390,24 +29392,6 @@ function registerInitCommand(program2) {
|
|
|
29390
29392
|
]);
|
|
29391
29393
|
token = answer.token;
|
|
29392
29394
|
}
|
|
29393
|
-
const { password } = await dist_default12.prompt([
|
|
29394
|
-
{
|
|
29395
|
-
type: "password",
|
|
29396
|
-
name: "password",
|
|
29397
|
-
message: "Set your encryption password (encrypts data locally):",
|
|
29398
|
-
mask: "*",
|
|
29399
|
-
validate: (v) => v.length >= 8 || "Password must be at least 8 characters"
|
|
29400
|
-
}
|
|
29401
|
-
]);
|
|
29402
|
-
const { confirmPassword } = await dist_default12.prompt([
|
|
29403
|
-
{
|
|
29404
|
-
type: "password",
|
|
29405
|
-
name: "confirmPassword",
|
|
29406
|
-
message: "Confirm encryption password:",
|
|
29407
|
-
mask: "*",
|
|
29408
|
-
validate: (v) => v === password || "Passwords do not match"
|
|
29409
|
-
}
|
|
29410
|
-
]);
|
|
29411
29395
|
const { deviceName } = await dist_default12.prompt([
|
|
29412
29396
|
{
|
|
29413
29397
|
type: "input",
|
|
@@ -29417,30 +29401,105 @@ function registerInitCommand(program2) {
|
|
|
29417
29401
|
}
|
|
29418
29402
|
]);
|
|
29419
29403
|
const spinner = ora("Setting up...").start();
|
|
29404
|
+
let keypair;
|
|
29405
|
+
let publicKeyB64;
|
|
29406
|
+
let privateKeyB64;
|
|
29407
|
+
let deviceId;
|
|
29408
|
+
let existingSalt;
|
|
29420
29409
|
try {
|
|
29421
29410
|
spinner.text = "Generating device keypair...";
|
|
29422
|
-
|
|
29423
|
-
|
|
29424
|
-
|
|
29411
|
+
keypair = await generateDeviceKeypair();
|
|
29412
|
+
publicKeyB64 = await exportPublicKey(keypair.publicKey);
|
|
29413
|
+
privateKeyB64 = await exportPrivateKey(keypair.privateKey);
|
|
29425
29414
|
spinner.text = "Registering device...";
|
|
29426
29415
|
const client = new CcsiniClient("https://ccsini-api.anis-maisara190.workers.dev", "");
|
|
29427
|
-
const
|
|
29428
|
-
|
|
29429
|
-
|
|
29430
|
-
|
|
29431
|
-
|
|
29432
|
-
|
|
29433
|
-
|
|
29416
|
+
const result = await client.registerDevice(token, deviceName, publicKeyB64, detectPlatform());
|
|
29417
|
+
deviceId = result.deviceId;
|
|
29418
|
+
existingSalt = result.salt;
|
|
29419
|
+
spinner.stop();
|
|
29420
|
+
} catch (e) {
|
|
29421
|
+
spinner.fail(e.message);
|
|
29422
|
+
process.exit(1);
|
|
29423
|
+
}
|
|
29424
|
+
const isMultiDevice = !!existingSalt;
|
|
29425
|
+
let masterKey;
|
|
29426
|
+
let salt;
|
|
29427
|
+
if (isMultiDevice) {
|
|
29428
|
+
salt = new Uint8Array(Buffer.from(existingSalt, "hex"));
|
|
29429
|
+
const MAX_ATTEMPTS = 3;
|
|
29430
|
+
for (let attempt = 1;attempt <= MAX_ATTEMPTS; attempt++) {
|
|
29431
|
+
const { password } = await dist_default12.prompt([
|
|
29432
|
+
{
|
|
29433
|
+
type: "password",
|
|
29434
|
+
name: "password",
|
|
29435
|
+
message: "Enter your encryption password (same as your first device):",
|
|
29436
|
+
mask: "*",
|
|
29437
|
+
validate: (v) => v.length >= 8 || "Password must be at least 8 characters"
|
|
29438
|
+
}
|
|
29439
|
+
]);
|
|
29440
|
+
const derivingSpinner = ora("Deriving encryption key...").start();
|
|
29441
|
+
masterKey = await deriveKeyFromPassphrase(password, salt);
|
|
29442
|
+
try {
|
|
29443
|
+
const { importPrivateKey: importPrivateKey2, createDeviceJWT: createDeviceJWT2 } = await Promise.resolve().then(() => (init_auth(), exports_auth));
|
|
29444
|
+
const privateKey = await importPrivateKey2(privateKeyB64);
|
|
29445
|
+
const jwt = await createDeviceJWT2(privateKey, deviceId);
|
|
29446
|
+
const authedClient = new CcsiniClient("https://ccsini-api.anis-maisara190.workers.dev", jwt);
|
|
29447
|
+
derivingSpinner.text = "Validating password...";
|
|
29448
|
+
const manifestEnc = await authedClient.getManifest();
|
|
29449
|
+
if (manifestEnc) {
|
|
29450
|
+
decryptFile(masterKey, "__manifest__", manifestEnc);
|
|
29451
|
+
}
|
|
29452
|
+
derivingSpinner.stop();
|
|
29453
|
+
break;
|
|
29454
|
+
} catch {
|
|
29455
|
+
derivingSpinner.stop();
|
|
29456
|
+
if (attempt < MAX_ATTEMPTS) {
|
|
29457
|
+
console.log(source_default.red(` Password doesn't match your first device. ${MAX_ATTEMPTS - attempt} attempt(s) remaining.`));
|
|
29458
|
+
} else {
|
|
29459
|
+
console.log(source_default.red(`
|
|
29460
|
+
Too many failed attempts. Please verify your password and try again.`));
|
|
29461
|
+
process.exit(1);
|
|
29462
|
+
}
|
|
29463
|
+
}
|
|
29434
29464
|
}
|
|
29435
|
-
|
|
29436
|
-
|
|
29465
|
+
} else {
|
|
29466
|
+
const { password } = await dist_default12.prompt([
|
|
29467
|
+
{
|
|
29468
|
+
type: "password",
|
|
29469
|
+
name: "password",
|
|
29470
|
+
message: "Set your encryption password (encrypts data locally):",
|
|
29471
|
+
mask: "*",
|
|
29472
|
+
validate: (v) => v.length >= 8 || "Password must be at least 8 characters"
|
|
29473
|
+
}
|
|
29474
|
+
]);
|
|
29475
|
+
await dist_default12.prompt([
|
|
29476
|
+
{
|
|
29477
|
+
type: "password",
|
|
29478
|
+
name: "confirmPassword",
|
|
29479
|
+
message: "Confirm encryption password:",
|
|
29480
|
+
mask: "*",
|
|
29481
|
+
validate: (v) => v === password || "Passwords do not match"
|
|
29482
|
+
}
|
|
29483
|
+
]);
|
|
29484
|
+
salt = crypto.getRandomValues(new Uint8Array(32));
|
|
29485
|
+
const derivingSpinner = ora("Deriving encryption key...").start();
|
|
29486
|
+
masterKey = await deriveKeyFromPassphrase(password, salt);
|
|
29487
|
+
derivingSpinner.stop();
|
|
29488
|
+
const uploadSpinner = ora("Uploading encryption salt...").start();
|
|
29489
|
+
try {
|
|
29437
29490
|
const { importPrivateKey: importPrivateKey2, createDeviceJWT: createDeviceJWT2 } = await Promise.resolve().then(() => (init_auth(), exports_auth));
|
|
29438
29491
|
const privateKey = await importPrivateKey2(privateKeyB64);
|
|
29439
29492
|
const jwt = await createDeviceJWT2(privateKey, deviceId);
|
|
29440
29493
|
const authedClient = new CcsiniClient("https://ccsini-api.anis-maisara190.workers.dev", jwt);
|
|
29441
29494
|
await authedClient.putSalt(Buffer.from(salt).toString("hex"));
|
|
29495
|
+
uploadSpinner.stop();
|
|
29496
|
+
} catch (e) {
|
|
29497
|
+
uploadSpinner.fail(e.message);
|
|
29498
|
+
process.exit(1);
|
|
29442
29499
|
}
|
|
29443
|
-
|
|
29500
|
+
}
|
|
29501
|
+
const saveSpinner = ora("Saving configuration...").start();
|
|
29502
|
+
try {
|
|
29444
29503
|
await saveKeys(configDir, {
|
|
29445
29504
|
salt,
|
|
29446
29505
|
devicePrivateKey: privateKeyB64,
|
|
@@ -29449,10 +29508,13 @@ function registerInitCommand(program2) {
|
|
|
29449
29508
|
deviceName,
|
|
29450
29509
|
apiUrl: "https://ccsini-api.anis-maisara190.workers.dev"
|
|
29451
29510
|
});
|
|
29511
|
+
await writeFile6(join7(configDir, ".cached-key"), masterKey, {
|
|
29512
|
+
mode: 384
|
|
29513
|
+
});
|
|
29452
29514
|
await saveDefaultSchema(configDir);
|
|
29453
|
-
|
|
29515
|
+
saveSpinner.text = "Installing Claude Code hooks...";
|
|
29454
29516
|
await installHooks(getClaudeDir());
|
|
29455
|
-
|
|
29517
|
+
saveSpinner.succeed("Setup complete!");
|
|
29456
29518
|
console.log(source_default.green(`
|
|
29457
29519
|
\u2713 Encryption keys generated`));
|
|
29458
29520
|
console.log(source_default.green(" \u2713 Device registered"));
|
|
@@ -29462,7 +29524,7 @@ function registerInitCommand(program2) {
|
|
|
29462
29524
|
Just use 'claude' as normal. Sync happens automatically.
|
|
29463
29525
|
`));
|
|
29464
29526
|
} catch (e) {
|
|
29465
|
-
|
|
29527
|
+
saveSpinner.fail(e.message);
|
|
29466
29528
|
process.exit(1);
|
|
29467
29529
|
}
|
|
29468
29530
|
});
|
|
@@ -29479,10 +29541,10 @@ function detectPlatform() {
|
|
|
29479
29541
|
// src/commands/auto.ts
|
|
29480
29542
|
init_auth();
|
|
29481
29543
|
init_auth();
|
|
29482
|
-
import { readFile as readFile7, writeFile as
|
|
29483
|
-
import { join as
|
|
29544
|
+
import { readFile as readFile7, writeFile as writeFile7 } from "fs/promises";
|
|
29545
|
+
import { join as join8 } from "path";
|
|
29484
29546
|
async function getMasterKey(configDir) {
|
|
29485
|
-
const cachedKeyPath =
|
|
29547
|
+
const cachedKeyPath = join8(configDir, ".cached-key");
|
|
29486
29548
|
try {
|
|
29487
29549
|
const cached = await readFile7(cachedKeyPath);
|
|
29488
29550
|
return new Uint8Array(cached);
|
|
@@ -29542,7 +29604,7 @@ function registerAutoCommands(program2) {
|
|
|
29542
29604
|
]);
|
|
29543
29605
|
const config = await loadKeys(configDir);
|
|
29544
29606
|
const masterKey = await deriveKeyFromPassphrase(password, config.salt);
|
|
29545
|
-
await
|
|
29607
|
+
await writeFile7(join8(configDir, ".cached-key"), masterKey, {
|
|
29546
29608
|
mode: 384
|
|
29547
29609
|
});
|
|
29548
29610
|
console.log("Unlocked. Auto-sync is now active.");
|
|
@@ -29551,7 +29613,7 @@ function registerAutoCommands(program2) {
|
|
|
29551
29613
|
const configDir = getConfigDir();
|
|
29552
29614
|
const { rm } = await import("fs/promises");
|
|
29553
29615
|
try {
|
|
29554
|
-
await rm(
|
|
29616
|
+
await rm(join8(configDir, ".cached-key"));
|
|
29555
29617
|
console.log("Locked. Auto-sync paused until next unlock.");
|
|
29556
29618
|
} catch {
|
|
29557
29619
|
console.log("Already locked.");
|
|
@@ -29562,7 +29624,7 @@ function registerAutoCommands(program2) {
|
|
|
29562
29624
|
// src/commands/doctor.ts
|
|
29563
29625
|
init_source();
|
|
29564
29626
|
import { access as access2 } from "fs/promises";
|
|
29565
|
-
import { join as
|
|
29627
|
+
import { join as join9 } from "path";
|
|
29566
29628
|
function registerDoctorCommand(program2) {
|
|
29567
29629
|
program2.command("doctor").description("Diagnose ccsini setup and connectivity").action(async () => {
|
|
29568
29630
|
const configDir = getConfigDir();
|
|
@@ -29604,7 +29666,7 @@ function registerDoctorCommand(program2) {
|
|
|
29604
29666
|
allGood = false;
|
|
29605
29667
|
}
|
|
29606
29668
|
try {
|
|
29607
|
-
await access2(
|
|
29669
|
+
await access2(join9(configDir, ".cached-key"));
|
|
29608
29670
|
console.log(source_default.green(" \u2713 Auto-sync unlocked"));
|
|
29609
29671
|
} catch {
|
|
29610
29672
|
console.log(source_default.yellow(" \u26A0 Auto-sync locked (run 'ccsini unlock')"));
|
|
@@ -29712,9 +29774,9 @@ Uninstall failed. Try manually:`);
|
|
|
29712
29774
|
// src/commands/sync.ts
|
|
29713
29775
|
init_auth();
|
|
29714
29776
|
import { readFile as readFile8 } from "fs/promises";
|
|
29715
|
-
import { join as
|
|
29777
|
+
import { join as join10 } from "path";
|
|
29716
29778
|
async function getMasterKey2(configDir) {
|
|
29717
|
-
const cachedKeyPath =
|
|
29779
|
+
const cachedKeyPath = join10(configDir, ".cached-key");
|
|
29718
29780
|
try {
|
|
29719
29781
|
const cached = await readFile8(cachedKeyPath);
|
|
29720
29782
|
return new Uint8Array(cached);
|
|
@@ -29730,8 +29792,8 @@ async function getMasterKey2(configDir) {
|
|
|
29730
29792
|
]);
|
|
29731
29793
|
const config = await loadKeys(configDir);
|
|
29732
29794
|
const masterKey = await deriveKeyFromPassphrase(password, config.salt);
|
|
29733
|
-
const { writeFile:
|
|
29734
|
-
await
|
|
29795
|
+
const { writeFile: writeFile8 } = await import("fs/promises");
|
|
29796
|
+
await writeFile8(cachedKeyPath, masterKey, { mode: 384 });
|
|
29735
29797
|
return masterKey;
|
|
29736
29798
|
}
|
|
29737
29799
|
}
|