codexuse-cli 5.0.6 → 5.0.7
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/README.md +3 -2
- package/dist/index.js +592 -79
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2616,13 +2616,15 @@ function createDefaultAppState() {
|
|
|
2616
2616
|
lastPushAt: null,
|
|
2617
2617
|
lastPullAt: null,
|
|
2618
2618
|
lastError: null,
|
|
2619
|
-
remoteUpdatedAt: null
|
|
2619
|
+
remoteUpdatedAt: null,
|
|
2620
|
+
remoteKind: "none"
|
|
2620
2621
|
},
|
|
2621
2622
|
analytics: {
|
|
2622
2623
|
anonymousId: null,
|
|
2623
2624
|
enabled: true,
|
|
2624
2625
|
lastFlushAt: null,
|
|
2625
|
-
lastError: null
|
|
2626
|
+
lastError: null,
|
|
2627
|
+
reportedNativeCrashIncidentIds: []
|
|
2626
2628
|
},
|
|
2627
2629
|
profilesByName: {}
|
|
2628
2630
|
};
|
|
@@ -3203,6 +3205,9 @@ function normalizeAppState(raw) {
|
|
|
3203
3205
|
merged.sync.lastPullAt = asString(merged.sync.lastPullAt);
|
|
3204
3206
|
merged.sync.lastError = asString(merged.sync.lastError);
|
|
3205
3207
|
merged.sync.remoteUpdatedAt = asString(merged.sync.remoteUpdatedAt);
|
|
3208
|
+
if (merged.sync.remoteKind !== "legacy-plaintext" && merged.sync.remoteKind !== "encrypted") {
|
|
3209
|
+
merged.sync.remoteKind = "none";
|
|
3210
|
+
}
|
|
3206
3211
|
if (!isRecord2(merged.analytics)) {
|
|
3207
3212
|
merged.analytics = clone2(defaults.analytics);
|
|
3208
3213
|
}
|
|
@@ -3212,6 +3217,9 @@ function normalizeAppState(raw) {
|
|
|
3212
3217
|
}
|
|
3213
3218
|
merged.analytics.lastFlushAt = asString(merged.analytics.lastFlushAt);
|
|
3214
3219
|
merged.analytics.lastError = asString(merged.analytics.lastError);
|
|
3220
|
+
merged.analytics.reportedNativeCrashIncidentIds = asStringArray(
|
|
3221
|
+
merged.analytics.reportedNativeCrashIncidentIds
|
|
3222
|
+
).slice(-20);
|
|
3215
3223
|
if ("telemetry" in merged) {
|
|
3216
3224
|
delete merged.telemetry;
|
|
3217
3225
|
}
|
|
@@ -7294,8 +7302,8 @@ Usage:
|
|
|
7294
7302
|
codexuse license activate <license-key>
|
|
7295
7303
|
|
|
7296
7304
|
codexuse sync status
|
|
7297
|
-
codexuse sync pull
|
|
7298
|
-
codexuse sync push
|
|
7305
|
+
codexuse sync pull [--passphrase-stdin]
|
|
7306
|
+
codexuse sync push [--passphrase-stdin]
|
|
7299
7307
|
|
|
7300
7308
|
Flags:
|
|
7301
7309
|
-h, --help Show help
|
|
@@ -7313,7 +7321,9 @@ Flags:
|
|
|
7313
7321
|
--profile=NAME Run Codex with one saved profile
|
|
7314
7322
|
--runtime=NAME Accounts Pool runtime store: desktop
|
|
7315
7323
|
--state-dir=PATH Override the runtime state dir for Accounts Pool inspection
|
|
7324
|
+
--passphrase-stdin Read Cloud Sync passphrase from stdin
|
|
7316
7325
|
Note: profile autoroll requires Pro.
|
|
7326
|
+
Cloud Sync: set CODEXUSE_SYNC_PASSPHRASE or use --passphrase-stdin unless the passphrase is saved in Keychain.
|
|
7317
7327
|
`);
|
|
7318
7328
|
}
|
|
7319
7329
|
|
|
@@ -9544,7 +9554,7 @@ function buildInCodexStatusOverlayCssRules() {
|
|
|
9544
9554
|
`${id}[data-open='false']:not([data-collapsed='true']):hover .codexuse-status-trigger{padding:8px 10px;gap:8px;}`,
|
|
9545
9555
|
`${id}[data-open='false']:not([data-collapsed='true']):hover .codexuse-status-label{max-width:160px;font-size:12px;}`,
|
|
9546
9556
|
`${id}[data-open='false']:not([data-collapsed='true']):hover .codexuse-status-chip{display:inline-flex;}`,
|
|
9547
|
-
`${id} .codexuse-action-menu{display:none;position:absolute;right:0;bottom:calc(100% + 8px);width:min(280px,calc(100vw - 24px));border:1px solid var(--cu-border);border-radius:12px;background:var(--cu-popover);padding:6px;box-shadow:0 12px 36px rgba(0,0,0,.32);}`,
|
|
9557
|
+
`${id} .codexuse-action-menu{display:none;position:absolute;right:0;bottom:calc(100% + 8px);width:min(280px,calc(100vw - 24px));max-height:min(420px,calc(100vh - 32px));overflow-y:auto;border:1px solid var(--cu-border);border-radius:12px;background:var(--cu-popover);padding:6px;box-shadow:0 12px 36px rgba(0,0,0,.32);}`,
|
|
9548
9558
|
`${id}[data-drop='down'] .codexuse-action-menu{bottom:auto;top:calc(100% + 8px);}`,
|
|
9549
9559
|
`${id}[data-open='true'] .codexuse-action-menu{display:flex;flex-direction:column;gap:2px;}`,
|
|
9550
9560
|
`${id} .codexuse-target-list{display:flex;max-height:210px;flex-direction:column;gap:2px;overflow-y:auto;}`,
|
|
@@ -9566,10 +9576,10 @@ function buildInCodexStatusOverlayCssRules() {
|
|
|
9566
9576
|
`${id} .codexuse-intro-detail{margin-top:2px;font-size:10px;color:var(--cu-muted);}`,
|
|
9567
9577
|
`${id} .codexuse-decision-secondary{border:1px solid var(--cu-border)!important;color:var(--cu-muted)!important;}`,
|
|
9568
9578
|
`${id} .codexuse-menu-divider{height:1px;margin:4px 2px;background:var(--cu-border);}`,
|
|
9569
|
-
`${id} .codexuse-command-row{display:flex;width:100%;align-items:center;justify-content:space-between;gap:10px;padding:6px 9px;border-radius:8px;cursor:pointer;text-align:left;transition:background 120ms ease-out;}`,
|
|
9570
|
-
`${id} .codexuse-command-row:hover{background:var(--cu-hover);}`,
|
|
9571
9579
|
`${id} .codexuse-setting-row{display:flex;width:100%;align-items:center;justify-content:space-between;gap:10px;padding:6px 9px;border-radius:8px;cursor:pointer;text-align:left;transition:background 120ms ease-out;}`,
|
|
9572
9580
|
`${id} .codexuse-setting-row:hover{background:var(--cu-hover);}`,
|
|
9581
|
+
`${id} .codexuse-setting-copy{display:flex;min-width:0;flex:1;flex-direction:column;gap:1px;}`,
|
|
9582
|
+
`${id} .codexuse-setting-copy .codexuse-target-detail{min-width:0;flex-shrink:1;overflow:hidden;text-overflow:ellipsis;}`,
|
|
9573
9583
|
`${id} .codexuse-toggle{position:relative;flex-shrink:0;width:26px;height:15px;border-radius:999px;background:var(--cu-border);transition:background 120ms ease-out;}`,
|
|
9574
9584
|
`${id} .codexuse-toggle::after{content:'';position:absolute;left:2px;top:2px;width:11px;height:11px;border-radius:50%;background:var(--cu-fg,#ececf1);transition:transform 120ms ease-out;}`,
|
|
9575
9585
|
`${id} .codexuse-setting-row[data-on='true'] .codexuse-toggle{background:var(--cu-accent);}`,
|
|
@@ -9578,13 +9588,17 @@ function buildInCodexStatusOverlayCssRules() {
|
|
|
9578
9588
|
`${id} .codexuse-action-status{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--cu-muted);font-size:10px;}`,
|
|
9579
9589
|
`${id} .codexuse-overlay-hide{flex-shrink:0;padding:2px 6px;border-radius:6px;color:var(--cu-muted);font-size:10px;cursor:pointer;}`,
|
|
9580
9590
|
`${id} .codexuse-overlay-hide:hover{background:var(--cu-hover);color:var(--cu-fg,#ececf1);}`,
|
|
9581
|
-
`${chip}{${palette}position:fixed;z-index:
|
|
9582
|
-
`${chip}:hover{background:var(--cu-hover);}`,
|
|
9583
|
-
`${chip}
|
|
9591
|
+
`${chip}{${palette}position:fixed;z-index:2147483002;display:inline-flex;align-items:center;gap:4px;border-radius:999px;border:1px solid var(--cu-border);background:var(--cu-surface);color:var(--cu-fg,#ececf1);font-family:inherit;font-size:11px;font-weight:600;line-height:1.2;white-space:nowrap;box-shadow:0 4px 16px rgba(0,0,0,.2);transition:background 120ms ease-out;pointer-events:auto;user-select:none;-webkit-user-select:none;}`,
|
|
9592
|
+
`${chip}:hover,${chip}[data-open='true']{background:var(--cu-hover);}`,
|
|
9593
|
+
`${chip}[data-disabled='true']{opacity:.6;}`,
|
|
9594
|
+
`${chip} button{font:inherit;font-family:inherit;color:inherit;border:0;background:transparent;}`,
|
|
9595
|
+
`${chip} .codexuse-handoff-main{display:inline-flex;align-items:center;padding:5px 8px 5px 10px;border-radius:999px;cursor:pointer;}`,
|
|
9596
|
+
`${chip} .codexuse-handoff-hide{display:inline-flex;width:20px;height:20px;align-items:center;justify-content:center;margin-right:3px;border-radius:50%;color:var(--cu-muted);cursor:pointer;font-size:12px;line-height:1;}`,
|
|
9597
|
+
`${chip} .codexuse-handoff-hide:hover{background:var(--cu-border);color:var(--cu-fg,#ececf1);}`,
|
|
9584
9598
|
// Hand-off account picker is a standalone body child (not inside the pill),
|
|
9585
9599
|
// so the pill-scoped popover rules don't reach it — give it its own palette
|
|
9586
9600
|
// + popover styling, mirroring the chip.
|
|
9587
|
-
`${picker}{${palette}position:fixed;z-index:
|
|
9601
|
+
`${picker}{${palette}position:fixed;z-index:2147483003;display:flex;flex-direction:column;gap:2px;width:min(280px,calc(100vw - 24px));max-height:240px;overflow-y:auto;border:1px solid var(--cu-border);border-radius:12px;background:var(--cu-popover);color:var(--cu-fg,#ececf1);font-family:inherit;font-size:12px;line-height:1.4;padding:6px;box-shadow:0 12px 36px rgba(0,0,0,.32);pointer-events:auto;}`,
|
|
9588
9602
|
`${picker} button{font:inherit;font-family:inherit;color:inherit;border:0;background:transparent;}`,
|
|
9589
9603
|
`${picker} .codexuse-target-list{display:flex;flex-direction:column;gap:2px;}`,
|
|
9590
9604
|
`${picker} .codexuse-target-row{display:flex;width:100%;align-items:center;justify-content:space-between;gap:10px;padding:7px 9px;border-radius:8px;cursor:pointer;text-align:left;transition:background 120ms ease-out;}`,
|
|
@@ -9616,6 +9630,9 @@ function createBridgeApplyQolExpression(settings) {
|
|
|
9616
9630
|
)};
|
|
9617
9631
|
const overlayAutoRollEnabled = ${JSON.stringify(
|
|
9618
9632
|
typeof settings.overlayAutoRollEnabled === "boolean" ? settings.overlayAutoRollEnabled : null
|
|
9633
|
+
)};
|
|
9634
|
+
const overlayRunningThreadHandoffEnabled = ${JSON.stringify(
|
|
9635
|
+
typeof settings.overlayRunningThreadHandoffEnabled === "boolean" ? settings.overlayRunningThreadHandoffEnabled : null
|
|
9619
9636
|
)};
|
|
9620
9637
|
const versions = {
|
|
9621
9638
|
wideView: "3",
|
|
@@ -9957,6 +9974,8 @@ function createBridgeApplyQolExpression(settings) {
|
|
|
9957
9974
|
const overlayHiddenKey = "codexuse:overlay:hidden";
|
|
9958
9975
|
const overlayIntroKey = "codexuse:overlay:intro-shown";
|
|
9959
9976
|
const overlayPosKey = "codexuse:overlay:pos";
|
|
9977
|
+
const handoffHiddenKey = "codexuse:handoff:hidden";
|
|
9978
|
+
const handoffPosKey = "codexuse:handoff:pos:v2";
|
|
9960
9979
|
const readOverlayStore = (key) => {
|
|
9961
9980
|
try {
|
|
9962
9981
|
return window.localStorage.getItem(key);
|
|
@@ -10055,6 +10074,41 @@ function createBridgeApplyQolExpression(settings) {
|
|
|
10055
10074
|
const y = Math.max(72, Math.min(140, Math.round(window.innerHeight * 0.16)));
|
|
10056
10075
|
placeOverlay(pill, x, y);
|
|
10057
10076
|
};
|
|
10077
|
+
const rectsOverlap = (a, b, gap = 0) =>
|
|
10078
|
+
a.left < b.right + gap &&
|
|
10079
|
+
a.right > b.left - gap &&
|
|
10080
|
+
a.top < b.bottom + gap &&
|
|
10081
|
+
a.bottom > b.top - gap;
|
|
10082
|
+
const positionedRect = (rect, pos) => ({
|
|
10083
|
+
left: pos.x,
|
|
10084
|
+
top: pos.y,
|
|
10085
|
+
right: pos.x + rect.width,
|
|
10086
|
+
bottom: pos.y + rect.height
|
|
10087
|
+
});
|
|
10088
|
+
const placeInitialHandoffPosition = (chip, anchorRect = null) => {
|
|
10089
|
+
const rect = chip.getBoundingClientRect();
|
|
10090
|
+
if (anchorRect && rect.width > 0 && rect.height > 0) {
|
|
10091
|
+
const gap = 8;
|
|
10092
|
+
const middleY = Math.round(anchorRect.top + (anchorRect.height - rect.height) / 2);
|
|
10093
|
+
const candidates = [
|
|
10094
|
+
{ x: anchorRect.right + gap, y: middleY },
|
|
10095
|
+
{ x: anchorRect.left - rect.width - gap, y: middleY },
|
|
10096
|
+
{ x: anchorRect.right - rect.width, y: anchorRect.top - rect.height - gap },
|
|
10097
|
+
{ x: anchorRect.left, y: anchorRect.top - rect.height - gap },
|
|
10098
|
+
{ x: anchorRect.right - rect.width, y: anchorRect.bottom + gap }
|
|
10099
|
+
];
|
|
10100
|
+
for (const candidate of candidates) {
|
|
10101
|
+
const next = clampOverlayXY(chip, candidate.x, candidate.y);
|
|
10102
|
+
if (!rectsOverlap(positionedRect(rect, next), anchorRect, 6)) {
|
|
10103
|
+
placeOverlay(chip, next.x, next.y);
|
|
10104
|
+
return;
|
|
10105
|
+
}
|
|
10106
|
+
}
|
|
10107
|
+
}
|
|
10108
|
+
const x = Math.max(8, window.innerWidth - rect.width - 16);
|
|
10109
|
+
const y = Math.max(64, Math.min(128, Math.round(window.innerHeight * 0.14)));
|
|
10110
|
+
placeOverlay(chip, x, y);
|
|
10111
|
+
};
|
|
10058
10112
|
const setOverlayMessage = (value) => {
|
|
10059
10113
|
const node = document.querySelector("#" + statusId + " [data-codexuse-action-status]");
|
|
10060
10114
|
if (node) node.textContent = value || "";
|
|
@@ -10098,7 +10152,7 @@ function createBridgeApplyQolExpression(settings) {
|
|
|
10098
10152
|
state.lastActionRequest = payload;
|
|
10099
10153
|
setOverlayMessage(
|
|
10100
10154
|
action === "switch" ? "Switching\u2026"
|
|
10101
|
-
: action === "continue" ? "
|
|
10155
|
+
: action === "continue" ? "Continuing in another account\u2026"
|
|
10102
10156
|
: action === "auto-roll-accept" ? "Switching\u2026"
|
|
10103
10157
|
: action === "auto-roll-cancel" ? "Staying here"
|
|
10104
10158
|
: action === "restart" ? "Waiting to restart; keeping draft\u2026"
|
|
@@ -10259,7 +10313,7 @@ function createBridgeApplyQolExpression(settings) {
|
|
|
10259
10313
|
introTitle.textContent = "CodexUse controls";
|
|
10260
10314
|
const introDetail = document.createElement("div");
|
|
10261
10315
|
introDetail.className = "codexuse-intro-detail";
|
|
10262
|
-
introDetail.textContent = "Switch accounts,
|
|
10316
|
+
introDetail.textContent = "Switch accounts, tune CodexUse controls, and confirm Auto-roll from here. Drag to move, or Hide to dismiss.";
|
|
10263
10317
|
intro.appendChild(introTitle);
|
|
10264
10318
|
intro.appendChild(introDetail);
|
|
10265
10319
|
menu.appendChild(intro);
|
|
@@ -10383,34 +10437,92 @@ function createBridgeApplyQolExpression(settings) {
|
|
|
10383
10437
|
empty.textContent = "No other account ready";
|
|
10384
10438
|
menu.appendChild(empty);
|
|
10385
10439
|
}
|
|
10386
|
-
const
|
|
10387
|
-
|
|
10388
|
-
|
|
10389
|
-
|
|
10390
|
-
|
|
10391
|
-
|
|
10392
|
-
|
|
10393
|
-
|
|
10394
|
-
|
|
10395
|
-
|
|
10396
|
-
|
|
10397
|
-
|
|
10398
|
-
|
|
10399
|
-
|
|
10400
|
-
|
|
10401
|
-
|
|
10402
|
-
|
|
10403
|
-
|
|
10404
|
-
|
|
10405
|
-
|
|
10406
|
-
|
|
10407
|
-
|
|
10440
|
+
const appendSettingRow = (item) => {
|
|
10441
|
+
const row = document.createElement("button");
|
|
10442
|
+
row.type = "button";
|
|
10443
|
+
row.className = "codexuse-setting-row";
|
|
10444
|
+
row.dataset.key = item.key;
|
|
10445
|
+
row.dataset.on = item.enabled ? "true" : "false";
|
|
10446
|
+
row.title = item.detail;
|
|
10447
|
+
const copy = document.createElement("span");
|
|
10448
|
+
copy.className = "codexuse-setting-copy";
|
|
10449
|
+
const label = document.createElement("span");
|
|
10450
|
+
label.className = "codexuse-target-label";
|
|
10451
|
+
label.textContent = item.label;
|
|
10452
|
+
copy.appendChild(label);
|
|
10453
|
+
const detail = document.createElement("span");
|
|
10454
|
+
detail.className = "codexuse-target-detail";
|
|
10455
|
+
detail.textContent = item.detail;
|
|
10456
|
+
copy.appendChild(detail);
|
|
10457
|
+
const toggle = document.createElement("span");
|
|
10458
|
+
toggle.className = "codexuse-toggle";
|
|
10459
|
+
row.appendChild(copy);
|
|
10460
|
+
row.appendChild(toggle);
|
|
10461
|
+
row.addEventListener("click", (event) => {
|
|
10462
|
+
event.preventDefault();
|
|
10463
|
+
event.stopPropagation();
|
|
10464
|
+
const next = row.dataset.on !== "true";
|
|
10465
|
+
row.dataset.on = next ? "true" : "false";
|
|
10466
|
+
requestAction("setting", null, { key: item.key, value: next });
|
|
10467
|
+
}, true);
|
|
10468
|
+
menu.appendChild(row);
|
|
10469
|
+
};
|
|
10470
|
+
const settingRows = [
|
|
10471
|
+
{
|
|
10472
|
+
key: "autoRoll",
|
|
10473
|
+
label: "Auto-roll",
|
|
10474
|
+
detail: "Switch when quota is low",
|
|
10475
|
+
enabled: overlayAutoRollEnabled === true,
|
|
10476
|
+
},
|
|
10477
|
+
{
|
|
10478
|
+
key: "runningThreadHandoff",
|
|
10479
|
+
label: "Continue running threads",
|
|
10480
|
+
detail: "Beta \xB7 after account switch",
|
|
10481
|
+
enabled: overlayRunningThreadHandoffEnabled === true,
|
|
10482
|
+
},
|
|
10483
|
+
{
|
|
10484
|
+
key: "wideView",
|
|
10485
|
+
label: "Wide conversations",
|
|
10486
|
+
detail: "More message room",
|
|
10487
|
+
enabled: wideViewEnabled,
|
|
10488
|
+
},
|
|
10489
|
+
{
|
|
10490
|
+
key: "scrollRestore",
|
|
10491
|
+
label: "Remember position",
|
|
10492
|
+
detail: "Return to last spot",
|
|
10493
|
+
enabled: scrollRestoreEnabled,
|
|
10494
|
+
},
|
|
10495
|
+
{
|
|
10496
|
+
key: "conversationTimeline",
|
|
10497
|
+
label: "Jump to user turns",
|
|
10498
|
+
detail: "Show turn markers",
|
|
10499
|
+
enabled: conversationTimelineEnabled,
|
|
10500
|
+
},
|
|
10501
|
+
];
|
|
10502
|
+
const divider = document.createElement("div");
|
|
10503
|
+
divider.className = "codexuse-menu-divider";
|
|
10504
|
+
menu.appendChild(divider);
|
|
10505
|
+
settingRows.forEach(appendSettingRow);
|
|
10408
10506
|
const footer = document.createElement("div");
|
|
10409
10507
|
footer.className = "codexuse-menu-footer";
|
|
10410
10508
|
const actionStatus = document.createElement("span");
|
|
10411
10509
|
actionStatus.className = "codexuse-action-status";
|
|
10412
10510
|
actionStatus.setAttribute("data-codexuse-action-status", "true");
|
|
10413
10511
|
footer.appendChild(actionStatus);
|
|
10512
|
+
if (handoffChipEnabled && readOverlayStore(handoffHiddenKey) === "1") {
|
|
10513
|
+
const showHandoff = document.createElement("button");
|
|
10514
|
+
showHandoff.type = "button";
|
|
10515
|
+
showHandoff.className = "codexuse-overlay-hide";
|
|
10516
|
+
showHandoff.textContent = "Show handoff";
|
|
10517
|
+
showHandoff.addEventListener("click", (event) => {
|
|
10518
|
+
event.preventDefault();
|
|
10519
|
+
event.stopPropagation();
|
|
10520
|
+
writeOverlayStore(handoffHiddenKey, null);
|
|
10521
|
+
renderStatus();
|
|
10522
|
+
renderHandoff();
|
|
10523
|
+
}, true);
|
|
10524
|
+
footer.appendChild(showHandoff);
|
|
10525
|
+
}
|
|
10414
10526
|
const hide = document.createElement("button");
|
|
10415
10527
|
hide.type = "button";
|
|
10416
10528
|
hide.className = "codexuse-overlay-hide";
|
|
@@ -10436,7 +10548,7 @@ function createBridgeApplyQolExpression(settings) {
|
|
|
10436
10548
|
}
|
|
10437
10549
|
return true;
|
|
10438
10550
|
};
|
|
10439
|
-
// Thread-scoped hand-off control:
|
|
10551
|
+
// Thread-scoped hand-off control: separate draggable chip, only shown when
|
|
10440
10552
|
// a conversation is on screen and another account is ready to take over.
|
|
10441
10553
|
// Log the hand-off chip's visibility gate only when it CHANGES \u2014 this runs
|
|
10442
10554
|
// on every mutation tick, and the reason is the first question every
|
|
@@ -10446,9 +10558,17 @@ function createBridgeApplyQolExpression(settings) {
|
|
|
10446
10558
|
state.lastHandoffReason = reason;
|
|
10447
10559
|
cuLog("handoff.render", { reason, targets: switchable.length });
|
|
10448
10560
|
};
|
|
10561
|
+
let cleanupHandoffPicker = null;
|
|
10449
10562
|
const renderHandoff = () => {
|
|
10450
|
-
document.getElementById(handoffId)
|
|
10563
|
+
const previous = document.getElementById(handoffId);
|
|
10564
|
+
if (previous?.dataset.dragging === "true") return true;
|
|
10565
|
+
const wasOpen = previous?.dataset.open === "true";
|
|
10566
|
+
previous?.remove();
|
|
10451
10567
|
document.getElementById(handoffPickerId)?.remove();
|
|
10568
|
+
if (typeof cleanupHandoffPicker === "function") {
|
|
10569
|
+
cleanupHandoffPicker();
|
|
10570
|
+
cleanupHandoffPicker = null;
|
|
10571
|
+
}
|
|
10452
10572
|
if (!inCodexStatusEnabled || !handoffChipEnabled) {
|
|
10453
10573
|
reportHandoff("disabled");
|
|
10454
10574
|
return false;
|
|
@@ -10457,6 +10577,10 @@ function createBridgeApplyQolExpression(settings) {
|
|
|
10457
10577
|
reportHandoff("overlay-hidden");
|
|
10458
10578
|
return false;
|
|
10459
10579
|
}
|
|
10580
|
+
if (readOverlayStore(handoffHiddenKey) === "1") {
|
|
10581
|
+
reportHandoff("handoff-hidden");
|
|
10582
|
+
return false;
|
|
10583
|
+
}
|
|
10460
10584
|
// Codex desktop marks turns with data-turn-key / data-user-message-bubble;
|
|
10461
10585
|
// the ChatGPT-style selectors are kept as a fallback.
|
|
10462
10586
|
const inThread = Boolean(domActiveThreadId() || document.querySelector(
|
|
@@ -10473,22 +10597,28 @@ function createBridgeApplyQolExpression(settings) {
|
|
|
10473
10597
|
reportHandoff("no-composer");
|
|
10474
10598
|
return false;
|
|
10475
10599
|
}
|
|
10476
|
-
const
|
|
10477
|
-
const rect = composer.getBoundingClientRect();
|
|
10600
|
+
const rect = textbox.getBoundingClientRect();
|
|
10478
10601
|
if (rect.width <= 0 || rect.height <= 0) {
|
|
10479
10602
|
reportHandoff("composer-hidden");
|
|
10480
10603
|
return false;
|
|
10481
10604
|
}
|
|
10482
|
-
const
|
|
10483
|
-
const chipRight = Math.max(8, window.innerWidth - rect.right);
|
|
10484
|
-
const chip = document.createElement("button");
|
|
10485
|
-
chip.type = "button";
|
|
10605
|
+
const chip = document.createElement("div");
|
|
10486
10606
|
chip.id = handoffId;
|
|
10487
10607
|
applyOverlayTheme(chip);
|
|
10488
|
-
chip.
|
|
10489
|
-
chip.
|
|
10490
|
-
|
|
10491
|
-
|
|
10608
|
+
chip.title = "Choose an account, then continue this thread there";
|
|
10609
|
+
chip.dataset.open = wasOpen ? "true" : "false";
|
|
10610
|
+
const chipMain = document.createElement("button");
|
|
10611
|
+
chipMain.type = "button";
|
|
10612
|
+
chipMain.className = "codexuse-handoff-main";
|
|
10613
|
+
chipMain.textContent = "Continue in another account";
|
|
10614
|
+
const chipHide = document.createElement("button");
|
|
10615
|
+
chipHide.type = "button";
|
|
10616
|
+
chipHide.className = "codexuse-handoff-hide";
|
|
10617
|
+
chipHide.textContent = "x";
|
|
10618
|
+
chipHide.title = "Hide Continue in another account";
|
|
10619
|
+
chipHide.setAttribute("aria-label", "Hide Continue in another account");
|
|
10620
|
+
chip.appendChild(chipMain);
|
|
10621
|
+
chip.appendChild(chipHide);
|
|
10492
10622
|
// Hand off needs BOTH a thread (this chip only shows in-thread) and a
|
|
10493
10623
|
// target account. Clicking opens a picker of ready accounts; the chosen
|
|
10494
10624
|
// account becomes the explicit continue target (the request also carries
|
|
@@ -10496,26 +10626,47 @@ function createBridgeApplyQolExpression(settings) {
|
|
|
10496
10626
|
// the "continue" message is auto-sent there).
|
|
10497
10627
|
const closePicker = () => {
|
|
10498
10628
|
document.getElementById(handoffPickerId)?.remove();
|
|
10629
|
+
if (typeof cleanupHandoffPicker === "function") {
|
|
10630
|
+
cleanupHandoffPicker();
|
|
10631
|
+
cleanupHandoffPicker = null;
|
|
10632
|
+
}
|
|
10499
10633
|
chip.dataset.open = "false";
|
|
10500
10634
|
};
|
|
10501
10635
|
const handOffTo = (target) => {
|
|
10502
10636
|
closePicker();
|
|
10503
|
-
chip.disabled = true;
|
|
10504
|
-
|
|
10637
|
+
chip.dataset.disabled = "true";
|
|
10638
|
+
chipMain.textContent = "Continuing...";
|
|
10505
10639
|
requestAction("continue", target);
|
|
10506
10640
|
};
|
|
10641
|
+
const placePicker = (picker) => {
|
|
10642
|
+
const chipRect = chip.getBoundingClientRect();
|
|
10643
|
+
const pickerRect = picker.getBoundingClientRect();
|
|
10644
|
+
const width = pickerRect.width || Math.min(280, window.innerWidth - 24);
|
|
10645
|
+
const height = pickerRect.height || 120;
|
|
10646
|
+
const left = Math.min(
|
|
10647
|
+
Math.max(8, chipRect.right - width),
|
|
10648
|
+
Math.max(8, window.innerWidth - width - 8)
|
|
10649
|
+
);
|
|
10650
|
+
const below = chipRect.bottom + 6;
|
|
10651
|
+
const above = chipRect.top - height - 6;
|
|
10652
|
+
const top = below + height <= window.innerHeight - 8
|
|
10653
|
+
? below
|
|
10654
|
+
: Math.max(8, above);
|
|
10655
|
+
picker.style.left = left + "px";
|
|
10656
|
+
picker.style.top = Math.min(top, Math.max(8, window.innerHeight - height - 8)) + "px";
|
|
10657
|
+
picker.style.right = "auto";
|
|
10658
|
+
picker.style.bottom = "auto";
|
|
10659
|
+
};
|
|
10507
10660
|
const openPicker = (skipRefresh = false) => {
|
|
10508
10661
|
document.getElementById(handoffPickerId)?.remove();
|
|
10662
|
+
if (typeof cleanupHandoffPicker === "function") {
|
|
10663
|
+
cleanupHandoffPicker();
|
|
10664
|
+
cleanupHandoffPicker = null;
|
|
10665
|
+
}
|
|
10509
10666
|
const picker = document.createElement("div");
|
|
10510
10667
|
picker.id = handoffPickerId;
|
|
10511
10668
|
picker.className = "codexuse-action-menu";
|
|
10512
10669
|
applyOverlayTheme(picker);
|
|
10513
|
-
picker.style.position = "fixed";
|
|
10514
|
-
picker.style.right = chipRight + "px";
|
|
10515
|
-
picker.style.bottom = Math.max(8, window.innerHeight - chipTop + 4) + "px";
|
|
10516
|
-
picker.style.maxHeight = "240px";
|
|
10517
|
-
picker.style.overflowY = "auto";
|
|
10518
|
-
picker.style.zIndex = "2147483647";
|
|
10519
10670
|
const list = document.createElement("div");
|
|
10520
10671
|
list.className = "codexuse-target-list";
|
|
10521
10672
|
if (switchable.length === 0) {
|
|
@@ -10528,7 +10679,7 @@ function createBridgeApplyQolExpression(settings) {
|
|
|
10528
10679
|
const row = document.createElement("button");
|
|
10529
10680
|
row.type = "button";
|
|
10530
10681
|
row.className = "codexuse-target-row";
|
|
10531
|
-
row.title = "Continue this thread
|
|
10682
|
+
row.title = "Continue this thread in " + (target.label || "account");
|
|
10532
10683
|
const label = document.createElement("span");
|
|
10533
10684
|
label.className = "codexuse-target-label";
|
|
10534
10685
|
label.textContent = typeof target.label === "string" && target.label.trim() ? target.label.trim() : "Account";
|
|
@@ -10542,12 +10693,14 @@ function createBridgeApplyQolExpression(settings) {
|
|
|
10542
10693
|
row.addEventListener("click", (event) => {
|
|
10543
10694
|
event.preventDefault();
|
|
10544
10695
|
event.stopPropagation();
|
|
10696
|
+
event.stopImmediatePropagation?.();
|
|
10545
10697
|
handOffTo(target);
|
|
10546
10698
|
}, true);
|
|
10547
10699
|
list.appendChild(row);
|
|
10548
10700
|
});
|
|
10549
10701
|
picker.appendChild(list);
|
|
10550
10702
|
document.body.appendChild(picker);
|
|
10703
|
+
placePicker(picker);
|
|
10551
10704
|
chip.dataset.open = "true";
|
|
10552
10705
|
// Rebuild the open picker once fresh targets arrive; skipRefresh stops
|
|
10553
10706
|
// the rebuilt picker from requesting again in a loop.
|
|
@@ -10558,14 +10711,56 @@ function createBridgeApplyQolExpression(settings) {
|
|
|
10558
10711
|
}
|
|
10559
10712
|
const onDocPointer = (event) => {
|
|
10560
10713
|
if (picker.contains(event.target) || chip.contains(event.target)) return;
|
|
10561
|
-
document.removeEventListener("pointerdown", onDocPointer, true);
|
|
10562
10714
|
closePicker();
|
|
10563
10715
|
};
|
|
10716
|
+
const onKeyDown = (event) => {
|
|
10717
|
+
if (event.key === "Escape") closePicker();
|
|
10718
|
+
};
|
|
10564
10719
|
document.addEventListener("pointerdown", onDocPointer, true);
|
|
10720
|
+
document.addEventListener("keydown", onKeyDown, true);
|
|
10721
|
+
cleanupHandoffPicker = () => {
|
|
10722
|
+
document.removeEventListener("pointerdown", onDocPointer, true);
|
|
10723
|
+
document.removeEventListener("keydown", onKeyDown, true);
|
|
10724
|
+
};
|
|
10565
10725
|
};
|
|
10566
|
-
|
|
10726
|
+
let dragMoved = false;
|
|
10727
|
+
chip.addEventListener("pointerdown", (event) => {
|
|
10728
|
+
if (event.button !== 0 || event.target?.closest?.(".codexuse-handoff-hide")) return;
|
|
10729
|
+
event.stopPropagation();
|
|
10730
|
+
event.stopImmediatePropagation?.();
|
|
10731
|
+
const startX = event.clientX;
|
|
10732
|
+
const startY = event.clientY;
|
|
10733
|
+
const startRect = chip.getBoundingClientRect();
|
|
10734
|
+
const offsetX = startX - startRect.left;
|
|
10735
|
+
const offsetY = startY - startRect.top;
|
|
10736
|
+
dragMoved = false;
|
|
10737
|
+
const onMove = (moveEvent) => {
|
|
10738
|
+
if (!dragMoved && Math.hypot(moveEvent.clientX - startX, moveEvent.clientY - startY) < 4) return;
|
|
10739
|
+
dragMoved = true;
|
|
10740
|
+
chip.dataset.dragging = "true";
|
|
10741
|
+
closePicker();
|
|
10742
|
+
placeOverlay(chip, moveEvent.clientX - offsetX, moveEvent.clientY - offsetY);
|
|
10743
|
+
};
|
|
10744
|
+
const onUp = () => {
|
|
10745
|
+
window.removeEventListener("pointermove", onMove, true);
|
|
10746
|
+
window.removeEventListener("pointerup", onUp, true);
|
|
10747
|
+
if (chip.dataset.dragging === "true") {
|
|
10748
|
+
delete chip.dataset.dragging;
|
|
10749
|
+
const chipRect = chip.getBoundingClientRect();
|
|
10750
|
+
writeOverlayStore(handoffPosKey, JSON.stringify({ x: chipRect.left, y: chipRect.top }));
|
|
10751
|
+
}
|
|
10752
|
+
};
|
|
10753
|
+
window.addEventListener("pointermove", onMove, true);
|
|
10754
|
+
window.addEventListener("pointerup", onUp, true);
|
|
10755
|
+
}, true);
|
|
10756
|
+
chipMain.addEventListener("click", (event) => {
|
|
10567
10757
|
event.preventDefault();
|
|
10568
10758
|
event.stopPropagation();
|
|
10759
|
+
event.stopImmediatePropagation?.();
|
|
10760
|
+
if (dragMoved || chip.dataset.disabled === "true") {
|
|
10761
|
+
dragMoved = false;
|
|
10762
|
+
return;
|
|
10763
|
+
}
|
|
10569
10764
|
// Always make the user pick the destination account explicitly \u2014 never
|
|
10570
10765
|
// auto-hand-off to a server-chosen account (which could be out of quota).
|
|
10571
10766
|
if (chip.dataset.open === "true") {
|
|
@@ -10574,7 +10769,38 @@ function createBridgeApplyQolExpression(settings) {
|
|
|
10574
10769
|
openPicker();
|
|
10575
10770
|
}
|
|
10576
10771
|
}, true);
|
|
10772
|
+
chipHide.addEventListener("click", (event) => {
|
|
10773
|
+
event.preventDefault();
|
|
10774
|
+
event.stopPropagation();
|
|
10775
|
+
event.stopImmediatePropagation?.();
|
|
10776
|
+
writeOverlayStore(handoffHiddenKey, "1");
|
|
10777
|
+
closePicker();
|
|
10778
|
+
renderHandoff();
|
|
10779
|
+
renderStatus();
|
|
10780
|
+
}, true);
|
|
10577
10781
|
document.body.appendChild(chip);
|
|
10782
|
+
const rawPos = readOverlayStore(handoffPosKey);
|
|
10783
|
+
if (rawPos) {
|
|
10784
|
+
try {
|
|
10785
|
+
const pos = JSON.parse(rawPos);
|
|
10786
|
+
if (typeof pos?.x === "number" && typeof pos?.y === "number") {
|
|
10787
|
+
const next = clampOverlayXY(chip, pos.x, pos.y);
|
|
10788
|
+
const chipRect = chip.getBoundingClientRect();
|
|
10789
|
+
if (rectsOverlap(positionedRect(chipRect, next), rect, 6)) {
|
|
10790
|
+
placeInitialHandoffPosition(chip, rect);
|
|
10791
|
+
} else {
|
|
10792
|
+
placeOverlay(chip, next.x, next.y);
|
|
10793
|
+
}
|
|
10794
|
+
} else {
|
|
10795
|
+
placeInitialHandoffPosition(chip, rect);
|
|
10796
|
+
}
|
|
10797
|
+
} catch {
|
|
10798
|
+
placeInitialHandoffPosition(chip, rect);
|
|
10799
|
+
}
|
|
10800
|
+
} else {
|
|
10801
|
+
placeInitialHandoffPosition(chip, rect);
|
|
10802
|
+
}
|
|
10803
|
+
if (wasOpen) openPicker();
|
|
10578
10804
|
reportHandoff("rendered");
|
|
10579
10805
|
return true;
|
|
10580
10806
|
};
|
|
@@ -10626,12 +10852,16 @@ function createBridgeApplyQolExpression(settings) {
|
|
|
10626
10852
|
clearTimelineTargets();
|
|
10627
10853
|
document.getElementById(statusId)?.remove();
|
|
10628
10854
|
document.getElementById(handoffId)?.remove();
|
|
10855
|
+
document.getElementById(handoffPickerId)?.remove();
|
|
10856
|
+
if (typeof cleanupHandoffPicker === "function") cleanupHandoffPicker();
|
|
10629
10857
|
};
|
|
10630
10858
|
} else {
|
|
10631
10859
|
document.querySelectorAll("." + timelineClass).forEach((node) => node.remove());
|
|
10632
10860
|
clearTimelineTargets();
|
|
10633
10861
|
document.getElementById(statusId)?.remove();
|
|
10634
10862
|
document.getElementById(handoffId)?.remove();
|
|
10863
|
+
document.getElementById(handoffPickerId)?.remove();
|
|
10864
|
+
if (typeof cleanupHandoffPicker === "function") cleanupHandoffPicker();
|
|
10635
10865
|
}
|
|
10636
10866
|
|
|
10637
10867
|
state.wideViewEnabled = wideViewEnabled;
|
|
@@ -11926,7 +12156,8 @@ function normalizeOfficialCodexQolSettings2(value) {
|
|
|
11926
12156
|
actionTargets,
|
|
11927
12157
|
canonicalSyncLine: typeof value.canonicalSyncLine === "string" && value.canonicalSyncLine.trim() ? value.canonicalSyncLine.trim().slice(0, 40) : null,
|
|
11928
12158
|
autoRollDecision: normalizeOverlayAutoRollDecision(value.autoRollDecision),
|
|
11929
|
-
overlayAutoRollEnabled: typeof value.overlayAutoRollEnabled === "boolean" ? value.overlayAutoRollEnabled : null
|
|
12159
|
+
overlayAutoRollEnabled: typeof value.overlayAutoRollEnabled === "boolean" ? value.overlayAutoRollEnabled : null,
|
|
12160
|
+
overlayRunningThreadHandoffEnabled: typeof value.overlayRunningThreadHandoffEnabled === "boolean" ? value.overlayRunningThreadHandoffEnabled : null
|
|
11930
12161
|
};
|
|
11931
12162
|
}
|
|
11932
12163
|
function hasActiveQolSettings(settings) {
|
|
@@ -12753,7 +12984,7 @@ function startOfficialCodexBridgeActionListener(args) {
|
|
|
12753
12984
|
if (!action) {
|
|
12754
12985
|
return;
|
|
12755
12986
|
}
|
|
12756
|
-
const settingKey = payload.settingKey === "autoRoll" || payload.settingKey === "wideView" || payload.settingKey === "scrollRestore" || payload.settingKey === "conversationTimeline" || payload.settingKey === "handoffChip" ? payload.settingKey : null;
|
|
12987
|
+
const settingKey = payload.settingKey === "autoRoll" || payload.settingKey === "runningThreadHandoff" || payload.settingKey === "wideView" || payload.settingKey === "scrollRestore" || payload.settingKey === "conversationTimeline" || payload.settingKey === "handoffChip" ? payload.settingKey : null;
|
|
12757
12988
|
const settingValue = typeof payload.settingValue === "boolean" ? payload.settingValue : null;
|
|
12758
12989
|
if (action === "setting" && (!settingKey || settingValue === null)) {
|
|
12759
12990
|
return;
|
|
@@ -15118,7 +15349,8 @@ async function handleProfileCommand(args, version) {
|
|
|
15118
15349
|
}
|
|
15119
15350
|
|
|
15120
15351
|
// ../../packages/contracts/src/cloud-sync/types.ts
|
|
15121
|
-
var
|
|
15352
|
+
var CLOUD_SYNC_PLAINTEXT_SCHEMA_VERSION = 1;
|
|
15353
|
+
var CLOUD_SYNC_ENCRYPTED_SCHEMA_VERSION = 2;
|
|
15122
15354
|
|
|
15123
15355
|
// ../../packages/shared/src/core/type-guards.ts
|
|
15124
15356
|
function isRecord6(value) {
|
|
@@ -15158,6 +15390,12 @@ function buildSyncUrl(pathname) {
|
|
|
15158
15390
|
const normalizedPath = pathname.startsWith("/") ? pathname : `/${pathname}`;
|
|
15159
15391
|
return `${baseUrl}${normalizedPath}`;
|
|
15160
15392
|
}
|
|
15393
|
+
function normalizeSnapshotKind(value) {
|
|
15394
|
+
if (value === "encrypted" || value === "legacy-plaintext") {
|
|
15395
|
+
return value;
|
|
15396
|
+
}
|
|
15397
|
+
return "none";
|
|
15398
|
+
}
|
|
15161
15399
|
function normalizeSnapshot(value) {
|
|
15162
15400
|
if (!isRecord6(value)) {
|
|
15163
15401
|
return null;
|
|
@@ -15167,7 +15405,37 @@ function normalizeSnapshot(value) {
|
|
|
15167
15405
|
return null;
|
|
15168
15406
|
}
|
|
15169
15407
|
const schemaVersion = Number(value.schemaVersion);
|
|
15170
|
-
if (
|
|
15408
|
+
if (schemaVersion === CLOUD_SYNC_ENCRYPTED_SCHEMA_VERSION) {
|
|
15409
|
+
if (!isRecord6(value.encryption)) {
|
|
15410
|
+
return null;
|
|
15411
|
+
}
|
|
15412
|
+
const encryption = value.encryption;
|
|
15413
|
+
const params = isRecord6(encryption.kdfParams) ? encryption.kdfParams : null;
|
|
15414
|
+
if (!params) {
|
|
15415
|
+
return null;
|
|
15416
|
+
}
|
|
15417
|
+
const N = Number(params.N);
|
|
15418
|
+
const r = Number(params.r);
|
|
15419
|
+
const p = Number(params.p);
|
|
15420
|
+
const keyLength = Number(params.keyLength);
|
|
15421
|
+
if (encryption.cipher !== "aes-256-gcm" || encryption.kdf !== "scrypt" || !Number.isSafeInteger(N) || !Number.isSafeInteger(r) || !Number.isSafeInteger(p) || !Number.isSafeInteger(keyLength) || keyLength !== 32 || typeof encryption.salt !== "string" || typeof encryption.iv !== "string" || typeof encryption.tag !== "string" || typeof encryption.ciphertext !== "string") {
|
|
15422
|
+
return null;
|
|
15423
|
+
}
|
|
15424
|
+
return {
|
|
15425
|
+
schemaVersion: CLOUD_SYNC_ENCRYPTED_SCHEMA_VERSION,
|
|
15426
|
+
updatedAt,
|
|
15427
|
+
encryption: {
|
|
15428
|
+
cipher: "aes-256-gcm",
|
|
15429
|
+
kdf: "scrypt",
|
|
15430
|
+
kdfParams: { N, r, p, keyLength },
|
|
15431
|
+
salt: encryption.salt,
|
|
15432
|
+
iv: encryption.iv,
|
|
15433
|
+
tag: encryption.tag,
|
|
15434
|
+
ciphertext: encryption.ciphertext
|
|
15435
|
+
}
|
|
15436
|
+
};
|
|
15437
|
+
}
|
|
15438
|
+
if (schemaVersion !== CLOUD_SYNC_PLAINTEXT_SCHEMA_VERSION) {
|
|
15171
15439
|
return null;
|
|
15172
15440
|
}
|
|
15173
15441
|
const rawProfiles = Array.isArray(value.profiles) ? value.profiles : [];
|
|
@@ -15191,7 +15459,7 @@ function normalizeSnapshot(value) {
|
|
|
15191
15459
|
const rawSettings = value.settingsJson;
|
|
15192
15460
|
const settingsJson = isRecord6(rawSettings) ? rawSettings : null;
|
|
15193
15461
|
return {
|
|
15194
|
-
schemaVersion:
|
|
15462
|
+
schemaVersion: CLOUD_SYNC_PLAINTEXT_SCHEMA_VERSION,
|
|
15195
15463
|
updatedAt,
|
|
15196
15464
|
profiles,
|
|
15197
15465
|
configTomlContent: typeof value.configTomlContent === "string" ? value.configTomlContent : null,
|
|
@@ -15243,7 +15511,12 @@ async function fetchRemoteSnapshotMeta(licenseKey) {
|
|
|
15243
15511
|
"/v1/sync/snapshot/meta",
|
|
15244
15512
|
licenseKey
|
|
15245
15513
|
);
|
|
15246
|
-
|
|
15514
|
+
const updatedAt = toIsoOrNull(response.updatedAt);
|
|
15515
|
+
const snapshotKind = normalizeSnapshotKind(response.snapshotKind);
|
|
15516
|
+
return {
|
|
15517
|
+
updatedAt,
|
|
15518
|
+
snapshotKind: updatedAt && response.snapshotKind === void 0 ? "legacy-plaintext" : snapshotKind
|
|
15519
|
+
};
|
|
15247
15520
|
}
|
|
15248
15521
|
async function pushRemoteSnapshot(licenseKey, snapshot, options) {
|
|
15249
15522
|
const serializedSnapshot = typeof options?.serializedSnapshot === "string" ? options.serializedSnapshot : JSON.stringify(snapshot);
|
|
@@ -16224,6 +16497,170 @@ async function saveCodexConfigContent(content, options) {
|
|
|
16224
16497
|
return buildSnapshot(normalized, true, options);
|
|
16225
16498
|
}
|
|
16226
16499
|
|
|
16500
|
+
// ../../packages/runtime-profiles/src/cloud-sync/encryption.ts
|
|
16501
|
+
var import_node_child_process7 = require("child_process");
|
|
16502
|
+
var import_node_crypto6 = require("crypto");
|
|
16503
|
+
var KEYCHAIN_SERVICE = "CODEXUSE_CLOUD_SYNC_PASSPHRASE";
|
|
16504
|
+
var KEYCHAIN_ACCOUNT_PREFIX = "license-sha256:";
|
|
16505
|
+
var ENCRYPTION_AAD = Buffer.from("codexuse-cloud-sync-v2", "utf8");
|
|
16506
|
+
var SCRYPT_PARAMS = {
|
|
16507
|
+
N: 32768,
|
|
16508
|
+
r: 8,
|
|
16509
|
+
p: 1,
|
|
16510
|
+
keyLength: 32
|
|
16511
|
+
};
|
|
16512
|
+
function normalizePassphrase(value) {
|
|
16513
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
16514
|
+
return null;
|
|
16515
|
+
}
|
|
16516
|
+
return value;
|
|
16517
|
+
}
|
|
16518
|
+
function requireCloudSyncPassphrase(value) {
|
|
16519
|
+
const normalized = normalizePassphrase(value);
|
|
16520
|
+
if (!normalized) {
|
|
16521
|
+
throw new Error("Cloud Sync passphrase is required.");
|
|
16522
|
+
}
|
|
16523
|
+
return normalized;
|
|
16524
|
+
}
|
|
16525
|
+
async function deriveKey(passphrase, salt, params = SCRYPT_PARAMS) {
|
|
16526
|
+
return new Promise((resolve, reject) => {
|
|
16527
|
+
(0, import_node_crypto6.scrypt)(passphrase, salt, params.keyLength, {
|
|
16528
|
+
N: params.N,
|
|
16529
|
+
r: params.r,
|
|
16530
|
+
p: params.p,
|
|
16531
|
+
maxmem: 64 * 1024 * 1024
|
|
16532
|
+
}, (error, key) => {
|
|
16533
|
+
if (error) {
|
|
16534
|
+
reject(error);
|
|
16535
|
+
return;
|
|
16536
|
+
}
|
|
16537
|
+
resolve(Buffer.from(key));
|
|
16538
|
+
});
|
|
16539
|
+
});
|
|
16540
|
+
}
|
|
16541
|
+
function toBase64(value) {
|
|
16542
|
+
return value.toString("base64");
|
|
16543
|
+
}
|
|
16544
|
+
function fromBase64(value) {
|
|
16545
|
+
return Buffer.from(value, "base64");
|
|
16546
|
+
}
|
|
16547
|
+
function normalizeDecryptedSnapshot(value) {
|
|
16548
|
+
if (!isRecord6(value) || Number(value.schemaVersion) !== CLOUD_SYNC_PLAINTEXT_SCHEMA_VERSION) {
|
|
16549
|
+
throw new Error("Cloud Sync snapshot payload is invalid.");
|
|
16550
|
+
}
|
|
16551
|
+
const updatedAt = toIsoOrNull(value.updatedAt);
|
|
16552
|
+
if (!updatedAt) {
|
|
16553
|
+
throw new Error("Cloud Sync snapshot timestamp is invalid.");
|
|
16554
|
+
}
|
|
16555
|
+
return {
|
|
16556
|
+
schemaVersion: CLOUD_SYNC_PLAINTEXT_SCHEMA_VERSION,
|
|
16557
|
+
updatedAt,
|
|
16558
|
+
profiles: Array.isArray(value.profiles) ? value.profiles : [],
|
|
16559
|
+
configTomlContent: typeof value.configTomlContent === "string" ? value.configTomlContent : null,
|
|
16560
|
+
settingsJson: isRecord6(value.settingsJson) ? value.settingsJson : null
|
|
16561
|
+
};
|
|
16562
|
+
}
|
|
16563
|
+
async function encryptCloudSyncSnapshot(snapshot, passphrase) {
|
|
16564
|
+
const salt = (0, import_node_crypto6.randomBytes)(16);
|
|
16565
|
+
const iv = (0, import_node_crypto6.randomBytes)(12);
|
|
16566
|
+
const key = await deriveKey(requireCloudSyncPassphrase(passphrase), salt);
|
|
16567
|
+
const cipher = (0, import_node_crypto6.createCipheriv)("aes-256-gcm", key, iv);
|
|
16568
|
+
cipher.setAAD(ENCRYPTION_AAD);
|
|
16569
|
+
const plaintext = Buffer.from(JSON.stringify(snapshot), "utf8");
|
|
16570
|
+
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
16571
|
+
const tag = cipher.getAuthTag();
|
|
16572
|
+
const encryption = {
|
|
16573
|
+
cipher: "aes-256-gcm",
|
|
16574
|
+
kdf: "scrypt",
|
|
16575
|
+
kdfParams: SCRYPT_PARAMS,
|
|
16576
|
+
salt: toBase64(salt),
|
|
16577
|
+
iv: toBase64(iv),
|
|
16578
|
+
tag: toBase64(tag),
|
|
16579
|
+
ciphertext: toBase64(ciphertext)
|
|
16580
|
+
};
|
|
16581
|
+
return {
|
|
16582
|
+
schemaVersion: CLOUD_SYNC_ENCRYPTED_SCHEMA_VERSION,
|
|
16583
|
+
updatedAt: snapshot.updatedAt,
|
|
16584
|
+
encryption
|
|
16585
|
+
};
|
|
16586
|
+
}
|
|
16587
|
+
async function decryptCloudSyncSnapshot(snapshot, passphrase) {
|
|
16588
|
+
try {
|
|
16589
|
+
const salt = fromBase64(snapshot.encryption.salt);
|
|
16590
|
+
const iv = fromBase64(snapshot.encryption.iv);
|
|
16591
|
+
const tag = fromBase64(snapshot.encryption.tag);
|
|
16592
|
+
const ciphertext = fromBase64(snapshot.encryption.ciphertext);
|
|
16593
|
+
const key = await deriveKey(requireCloudSyncPassphrase(passphrase), salt, snapshot.encryption.kdfParams);
|
|
16594
|
+
const decipher = (0, import_node_crypto6.createDecipheriv)("aes-256-gcm", key, iv);
|
|
16595
|
+
decipher.setAAD(ENCRYPTION_AAD);
|
|
16596
|
+
decipher.setAuthTag(tag);
|
|
16597
|
+
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
16598
|
+
return normalizeDecryptedSnapshot(JSON.parse(plaintext.toString("utf8")));
|
|
16599
|
+
} catch (error) {
|
|
16600
|
+
if (error instanceof Error && error.message === "Cloud Sync passphrase is required.") {
|
|
16601
|
+
throw error;
|
|
16602
|
+
}
|
|
16603
|
+
const wrapped = new Error("Cloud Sync passphrase is incorrect or snapshot is corrupted.");
|
|
16604
|
+
wrapped.cause = error;
|
|
16605
|
+
throw wrapped;
|
|
16606
|
+
}
|
|
16607
|
+
}
|
|
16608
|
+
function keychainAccountForLicense(licenseKey) {
|
|
16609
|
+
const digest = (0, import_node_crypto6.createHash)("sha256").update(licenseKey).digest("hex");
|
|
16610
|
+
return KEYCHAIN_ACCOUNT_PREFIX + digest;
|
|
16611
|
+
}
|
|
16612
|
+
function runSecurityCommand(args) {
|
|
16613
|
+
return new Promise((resolve, reject) => {
|
|
16614
|
+
const child = (0, import_node_child_process7.spawn)("security", args, { stdio: ["ignore", "pipe", "ignore"] });
|
|
16615
|
+
let stdout = "";
|
|
16616
|
+
child.stdout?.on("data", (chunk) => {
|
|
16617
|
+
stdout += String(chunk);
|
|
16618
|
+
});
|
|
16619
|
+
child.on("error", () => {
|
|
16620
|
+
reject(new Error("keychain-command-failed"));
|
|
16621
|
+
});
|
|
16622
|
+
child.on("close", (code) => {
|
|
16623
|
+
resolve({ code, stdout });
|
|
16624
|
+
});
|
|
16625
|
+
});
|
|
16626
|
+
}
|
|
16627
|
+
async function readRememberedCloudSyncPassphrase(licenseKey) {
|
|
16628
|
+
if (process.platform !== "darwin") {
|
|
16629
|
+
return null;
|
|
16630
|
+
}
|
|
16631
|
+
const result = await runSecurityCommand([
|
|
16632
|
+
"find-generic-password",
|
|
16633
|
+
"-a",
|
|
16634
|
+
keychainAccountForLicense(licenseKey),
|
|
16635
|
+
"-s",
|
|
16636
|
+
KEYCHAIN_SERVICE,
|
|
16637
|
+
"-w"
|
|
16638
|
+
]);
|
|
16639
|
+
if (result.code !== 0) {
|
|
16640
|
+
return null;
|
|
16641
|
+
}
|
|
16642
|
+
return result.stdout.length > 0 ? result.stdout.replace(/\n$/, "") : null;
|
|
16643
|
+
}
|
|
16644
|
+
async function writeRememberedCloudSyncPassphrase(licenseKey, passphrase) {
|
|
16645
|
+
if (process.platform !== "darwin") {
|
|
16646
|
+
throw new Error("keychain-unsupported");
|
|
16647
|
+
}
|
|
16648
|
+
const value = requireCloudSyncPassphrase(passphrase);
|
|
16649
|
+
const result = await runSecurityCommand([
|
|
16650
|
+
"add-generic-password",
|
|
16651
|
+
"-U",
|
|
16652
|
+
"-a",
|
|
16653
|
+
keychainAccountForLicense(licenseKey),
|
|
16654
|
+
"-s",
|
|
16655
|
+
KEYCHAIN_SERVICE,
|
|
16656
|
+
"-w",
|
|
16657
|
+
value
|
|
16658
|
+
]);
|
|
16659
|
+
if (result.code !== 0) {
|
|
16660
|
+
throw new Error("keychain-write-failed");
|
|
16661
|
+
}
|
|
16662
|
+
}
|
|
16663
|
+
|
|
16227
16664
|
// ../../packages/runtime-profiles/src/cloud-sync/service.ts
|
|
16228
16665
|
var SYNC_SIZE_WARN_BYTES = 1 * 1024 * 1024;
|
|
16229
16666
|
var SYNC_SIZE_MAX_BYTES = 5 * 1024 * 1024;
|
|
@@ -16276,7 +16713,8 @@ async function readState() {
|
|
|
16276
16713
|
lastPushAt: state.sync.lastPushAt ?? void 0,
|
|
16277
16714
|
lastPullAt: state.sync.lastPullAt ?? void 0,
|
|
16278
16715
|
lastError: state.sync.lastError ?? void 0,
|
|
16279
|
-
remoteUpdatedAt: state.sync.remoteUpdatedAt ?? void 0
|
|
16716
|
+
remoteUpdatedAt: state.sync.remoteUpdatedAt ?? void 0,
|
|
16717
|
+
remoteKind: state.sync.remoteKind ?? "none"
|
|
16280
16718
|
};
|
|
16281
16719
|
}
|
|
16282
16720
|
async function writeState(patch) {
|
|
@@ -16285,7 +16723,8 @@ async function writeState(patch) {
|
|
|
16285
16723
|
...typeof patch.lastPushAt === "string" ? { lastPushAt: patch.lastPushAt } : {},
|
|
16286
16724
|
...typeof patch.lastPullAt === "string" ? { lastPullAt: patch.lastPullAt } : {},
|
|
16287
16725
|
...typeof patch.lastError === "string" ? { lastError: patch.lastError } : patch.lastError === void 0 ? { lastError: null } : {},
|
|
16288
|
-
...typeof patch.remoteUpdatedAt === "string" ? { remoteUpdatedAt: patch.remoteUpdatedAt } : {}
|
|
16726
|
+
...typeof patch.remoteUpdatedAt === "string" ? { remoteUpdatedAt: patch.remoteUpdatedAt } : patch.remoteUpdatedAt === void 0 ? {} : { remoteUpdatedAt: null },
|
|
16727
|
+
...patch.remoteKind ? { remoteKind: patch.remoteKind } : {}
|
|
16289
16728
|
}
|
|
16290
16729
|
});
|
|
16291
16730
|
}
|
|
@@ -16338,7 +16777,7 @@ async function buildLocalSnapshot(profileManager, options = {}) {
|
|
|
16338
16777
|
throw new Error("Refusing to push an empty cloud sync snapshot.");
|
|
16339
16778
|
}
|
|
16340
16779
|
const snapshot = {
|
|
16341
|
-
schemaVersion:
|
|
16780
|
+
schemaVersion: CLOUD_SYNC_PLAINTEXT_SCHEMA_VERSION,
|
|
16342
16781
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16343
16782
|
profiles,
|
|
16344
16783
|
configTomlContent: config.exists ? config.content : null,
|
|
@@ -16363,6 +16802,34 @@ async function applyRemoteSnapshot(profileManager, snapshot) {
|
|
|
16363
16802
|
await writeCodexSettingsJsonRaw({});
|
|
16364
16803
|
}
|
|
16365
16804
|
}
|
|
16805
|
+
function getSnapshotKind(snapshot) {
|
|
16806
|
+
if (!snapshot) {
|
|
16807
|
+
return "none";
|
|
16808
|
+
}
|
|
16809
|
+
return snapshot.schemaVersion === CLOUD_SYNC_ENCRYPTED_SCHEMA_VERSION ? "encrypted" : "legacy-plaintext";
|
|
16810
|
+
}
|
|
16811
|
+
async function resolvePassphrase(licenseKey, options) {
|
|
16812
|
+
if (typeof options?.passphrase === "string" && options.passphrase.length > 0) {
|
|
16813
|
+
return { value: requireCloudSyncPassphrase(options.passphrase), source: "input" };
|
|
16814
|
+
}
|
|
16815
|
+
const remembered = await readRememberedCloudSyncPassphrase(licenseKey);
|
|
16816
|
+
if (remembered) {
|
|
16817
|
+
return { value: remembered, source: "keychain" };
|
|
16818
|
+
}
|
|
16819
|
+
throw new Error("Cloud Sync passphrase is required.");
|
|
16820
|
+
}
|
|
16821
|
+
async function rememberPassphraseIfRequested(licenseKey, options, passphrase) {
|
|
16822
|
+
if (options?.rememberPassphrase !== true || passphrase.source !== "input") {
|
|
16823
|
+
return;
|
|
16824
|
+
}
|
|
16825
|
+
try {
|
|
16826
|
+
await writeRememberedCloudSyncPassphrase(licenseKey, passphrase.value);
|
|
16827
|
+
} catch (error) {
|
|
16828
|
+
logWarn("[cloud-sync] failed to remember passphrase in keychain", {
|
|
16829
|
+
error: error instanceof Error ? error.message : String(error)
|
|
16830
|
+
});
|
|
16831
|
+
}
|
|
16832
|
+
}
|
|
16366
16833
|
function toRunError(mode, error) {
|
|
16367
16834
|
const message = formatUserFacingError(error, {
|
|
16368
16835
|
fallback: `Cloud sync ${mode} failed.`
|
|
@@ -16379,14 +16846,23 @@ async function getCloudSyncStatus() {
|
|
|
16379
16846
|
const eligibility = await resolveEligibility();
|
|
16380
16847
|
const state = await readState();
|
|
16381
16848
|
let remoteUpdatedAt = state.remoteUpdatedAt ?? null;
|
|
16849
|
+
let remoteKind = state.remoteKind ?? "none";
|
|
16850
|
+
let hasRememberedPassphrase = false;
|
|
16382
16851
|
if (eligibility.canSync && eligibility.licenseKey) {
|
|
16852
|
+
hasRememberedPassphrase = Boolean(
|
|
16853
|
+
await readRememberedCloudSyncPassphrase(eligibility.licenseKey).catch(() => null)
|
|
16854
|
+
);
|
|
16383
16855
|
try {
|
|
16384
|
-
|
|
16856
|
+
const remoteMeta = await fetchRemoteSnapshotMeta(eligibility.licenseKey);
|
|
16857
|
+
remoteUpdatedAt = remoteMeta.updatedAt;
|
|
16858
|
+
remoteKind = remoteMeta.snapshotKind;
|
|
16859
|
+
await writeState({ remoteUpdatedAt, remoteKind });
|
|
16385
16860
|
} catch (error) {
|
|
16386
16861
|
if (error instanceof CloudSyncClientError && error.status === 404) {
|
|
16387
16862
|
try {
|
|
16388
16863
|
const remote = await fetchRemoteSnapshot(eligibility.licenseKey);
|
|
16389
16864
|
remoteUpdatedAt = remote?.updatedAt ?? null;
|
|
16865
|
+
remoteKind = getSnapshotKind(remote);
|
|
16390
16866
|
} catch {
|
|
16391
16867
|
}
|
|
16392
16868
|
}
|
|
@@ -16397,13 +16873,15 @@ async function getCloudSyncStatus() {
|
|
|
16397
16873
|
reason: eligibility.reason,
|
|
16398
16874
|
licenseState: eligibility.licenseState,
|
|
16399
16875
|
hasLicenseKey: Boolean(eligibility.licenseKey),
|
|
16876
|
+
hasRememberedPassphrase,
|
|
16400
16877
|
lastPushAt: state.lastPushAt ?? null,
|
|
16401
16878
|
lastPullAt: state.lastPullAt ?? null,
|
|
16402
16879
|
lastError: state.lastError ?? null,
|
|
16403
|
-
remoteUpdatedAt
|
|
16880
|
+
remoteUpdatedAt,
|
|
16881
|
+
remoteKind
|
|
16404
16882
|
};
|
|
16405
16883
|
}
|
|
16406
|
-
async function pushCloudSync() {
|
|
16884
|
+
async function pushCloudSync(options = {}) {
|
|
16407
16885
|
const eligibility = await resolveEligibility();
|
|
16408
16886
|
if (!eligibility.canSync || !eligibility.licenseKey) {
|
|
16409
16887
|
return {
|
|
@@ -16418,7 +16896,9 @@ async function pushCloudSync() {
|
|
|
16418
16896
|
try {
|
|
16419
16897
|
await profileManager.initialize();
|
|
16420
16898
|
const localSnapshot = await buildLocalSnapshot(profileManager, { enforcePushGuards: true });
|
|
16421
|
-
const
|
|
16899
|
+
const passphrase = await resolvePassphrase(eligibility.licenseKey, options);
|
|
16900
|
+
const encryptedSnapshot = await encryptCloudSyncSnapshot(localSnapshot, passphrase.value);
|
|
16901
|
+
const serializedSnapshot = JSON.stringify(encryptedSnapshot);
|
|
16422
16902
|
const snapshotBytes = Buffer.byteLength(serializedSnapshot, "utf8");
|
|
16423
16903
|
if (snapshotBytes > SYNC_SIZE_WARN_BYTES) {
|
|
16424
16904
|
logWarn("[cloud-sync] push snapshot is large", {
|
|
@@ -16434,12 +16914,14 @@ async function pushCloudSync() {
|
|
|
16434
16914
|
if (process.env.NODE_ENV !== "production") {
|
|
16435
16915
|
logInfo("[cloud-sync] push snapshot summary", summarizeSnapshot(localSnapshot));
|
|
16436
16916
|
}
|
|
16437
|
-
const remote = await pushRemoteSnapshot(eligibility.licenseKey,
|
|
16917
|
+
const remote = await pushRemoteSnapshot(eligibility.licenseKey, encryptedSnapshot, {
|
|
16438
16918
|
serializedSnapshot
|
|
16439
16919
|
});
|
|
16920
|
+
const remoteKind = getSnapshotKind(remote.snapshot);
|
|
16440
16921
|
await writeState({
|
|
16441
16922
|
lastPushAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16442
16923
|
remoteUpdatedAt: remote.snapshot.updatedAt,
|
|
16924
|
+
remoteKind,
|
|
16443
16925
|
lastError: void 0
|
|
16444
16926
|
});
|
|
16445
16927
|
if (remote.status === "stale") {
|
|
@@ -16451,6 +16933,7 @@ async function pushCloudSync() {
|
|
|
16451
16933
|
remoteUpdatedAt: remote.snapshot.updatedAt
|
|
16452
16934
|
};
|
|
16453
16935
|
}
|
|
16936
|
+
await rememberPassphraseIfRequested(eligibility.licenseKey, options, passphrase);
|
|
16454
16937
|
return {
|
|
16455
16938
|
mode: "push",
|
|
16456
16939
|
status: "applied",
|
|
@@ -16465,7 +16948,7 @@ async function pushCloudSync() {
|
|
|
16465
16948
|
return result;
|
|
16466
16949
|
}
|
|
16467
16950
|
}
|
|
16468
|
-
async function pullCloudSync() {
|
|
16951
|
+
async function pullCloudSync(options = {}) {
|
|
16469
16952
|
const eligibility = await resolveEligibility();
|
|
16470
16953
|
if (!eligibility.canSync || !eligibility.licenseKey) {
|
|
16471
16954
|
return {
|
|
@@ -16481,6 +16964,7 @@ async function pullCloudSync() {
|
|
|
16481
16964
|
await profileManager.initialize();
|
|
16482
16965
|
const remote = await fetchRemoteSnapshot(eligibility.licenseKey);
|
|
16483
16966
|
if (!remote) {
|
|
16967
|
+
await writeState({ remoteUpdatedAt: null, remoteKind: "none" });
|
|
16484
16968
|
return {
|
|
16485
16969
|
mode: "pull",
|
|
16486
16970
|
status: "skipped",
|
|
@@ -16489,17 +16973,30 @@ async function pullCloudSync() {
|
|
|
16489
16973
|
remoteUpdatedAt: null
|
|
16490
16974
|
};
|
|
16491
16975
|
}
|
|
16492
|
-
|
|
16976
|
+
const remoteKind = getSnapshotKind(remote);
|
|
16977
|
+
let passphrase = null;
|
|
16978
|
+
let plainSnapshot;
|
|
16979
|
+
if (remote.schemaVersion === CLOUD_SYNC_ENCRYPTED_SCHEMA_VERSION) {
|
|
16980
|
+
passphrase = await resolvePassphrase(eligibility.licenseKey, options);
|
|
16981
|
+
plainSnapshot = await decryptCloudSyncSnapshot(remote, passphrase.value);
|
|
16982
|
+
} else {
|
|
16983
|
+
plainSnapshot = remote;
|
|
16984
|
+
}
|
|
16985
|
+
await applyRemoteSnapshot(profileManager, plainSnapshot);
|
|
16493
16986
|
await writeState({
|
|
16494
16987
|
lastPullAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16495
16988
|
remoteUpdatedAt: remote.updatedAt,
|
|
16989
|
+
remoteKind,
|
|
16496
16990
|
lastError: void 0
|
|
16497
16991
|
});
|
|
16992
|
+
if (passphrase) {
|
|
16993
|
+
await rememberPassphraseIfRequested(eligibility.licenseKey, options, passphrase);
|
|
16994
|
+
}
|
|
16498
16995
|
return {
|
|
16499
16996
|
mode: "pull",
|
|
16500
16997
|
status: "applied",
|
|
16501
|
-
message: "Cloud sync pull completed.",
|
|
16502
|
-
localUpdatedAt:
|
|
16998
|
+
message: remoteKind === "legacy-plaintext" ? "Legacy cloud sync pull completed. Push again to encrypt the remote snapshot." : "Cloud sync pull completed.",
|
|
16999
|
+
localUpdatedAt: plainSnapshot.updatedAt,
|
|
16503
17000
|
remoteUpdatedAt: remote.updatedAt
|
|
16504
17001
|
};
|
|
16505
17002
|
} catch (error) {
|
|
@@ -16511,6 +17008,20 @@ async function pullCloudSync() {
|
|
|
16511
17008
|
}
|
|
16512
17009
|
|
|
16513
17010
|
// src/commands/sync.ts
|
|
17011
|
+
async function readPassphraseFromStdin() {
|
|
17012
|
+
let value = "";
|
|
17013
|
+
for await (const chunk of process.stdin) {
|
|
17014
|
+
value += String(chunk);
|
|
17015
|
+
}
|
|
17016
|
+
return value.replace(/\r?\n$/, "");
|
|
17017
|
+
}
|
|
17018
|
+
async function resolvePassphraseOptions(flags) {
|
|
17019
|
+
if (hasFlag(flags, "--passphrase-stdin")) {
|
|
17020
|
+
return { passphrase: await readPassphraseFromStdin() };
|
|
17021
|
+
}
|
|
17022
|
+
const fromEnv = process.env.CODEXUSE_SYNC_PASSPHRASE;
|
|
17023
|
+
return { passphrase: typeof fromEnv === "string" && fromEnv.length > 0 ? fromEnv : null };
|
|
17024
|
+
}
|
|
16514
17025
|
function printSyncResult(result) {
|
|
16515
17026
|
console.log(result.message);
|
|
16516
17027
|
if (result.localUpdatedAt) {
|
|
@@ -16542,6 +17053,8 @@ async function handleSync(args, version) {
|
|
|
16542
17053
|
if (status.remoteUpdatedAt) {
|
|
16543
17054
|
console.log(`Remote snapshot: ${status.remoteUpdatedAt}`);
|
|
16544
17055
|
}
|
|
17056
|
+
console.log(`Remote kind: ${status.remoteKind}`);
|
|
17057
|
+
console.log(`Remembered passphrase: ${status.hasRememberedPassphrase ? "yes" : "no"}`);
|
|
16545
17058
|
if (status.lastPushAt) {
|
|
16546
17059
|
console.log(`Last push: ${status.lastPushAt}`);
|
|
16547
17060
|
}
|
|
@@ -16554,7 +17067,7 @@ async function handleSync(args, version) {
|
|
|
16554
17067
|
return;
|
|
16555
17068
|
}
|
|
16556
17069
|
case "pull": {
|
|
16557
|
-
const result = await pullCloudSync();
|
|
17070
|
+
const result = await pullCloudSync(await resolvePassphraseOptions(flags));
|
|
16558
17071
|
printSyncResult(result);
|
|
16559
17072
|
if (result.status === "error") {
|
|
16560
17073
|
process.exitCode = 1;
|
|
@@ -16562,7 +17075,7 @@ async function handleSync(args, version) {
|
|
|
16562
17075
|
return;
|
|
16563
17076
|
}
|
|
16564
17077
|
case "push": {
|
|
16565
|
-
const result = await pushCloudSync();
|
|
17078
|
+
const result = await pushCloudSync(await resolvePassphraseOptions(flags));
|
|
16566
17079
|
printSyncResult(result);
|
|
16567
17080
|
if (result.status === "error") {
|
|
16568
17081
|
process.exitCode = 1;
|
|
@@ -16590,7 +17103,7 @@ async function ensureCliStorageReady() {
|
|
|
16590
17103
|
}
|
|
16591
17104
|
|
|
16592
17105
|
// src/app/main.ts
|
|
16593
|
-
var VERSION = true ? "5.0.
|
|
17106
|
+
var VERSION = true ? "5.0.7" : "0.0.0";
|
|
16594
17107
|
async function runCli() {
|
|
16595
17108
|
const args = process.argv.slice(2);
|
|
16596
17109
|
if (args.length === 0) {
|