@runeya/runeya 2.0.121 → 2.0.122
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/{agent-manager-4HBMLHXU.js → agent-manager-BSPEFZKZ.js} +3 -3
- package/{chat-VL6BIVO5.js → chat-SE5GIT4B.js} +6 -6
- package/{chunk-HJUFIZ7H.js → chunk-BVBK2WII.js} +128 -158
- package/chunk-BVBK2WII.js.map +1 -0
- package/chunk-GL7WA5K3.js +92 -0
- package/chunk-GL7WA5K3.js.map +1 -0
- package/{chunk-3N55WR7F.js → chunk-NIU3CN5A.js} +7 -16
- package/chunk-NIU3CN5A.js.map +1 -0
- package/{chunk-OVV52N5F.js → chunk-VNLIA5PV.js} +78 -74
- package/chunk-VNLIA5PV.js.map +1 -0
- package/{chunk-CNTL6NVU.js → chunk-XTLQOYLT.js} +118 -58
- package/chunk-XTLQOYLT.js.map +1 -0
- package/{companion-AUMA6RGX.js → companion-HEJHC3UR.js} +4 -4
- package/index.js +3 -3
- package/package.json +1 -1
- package/{settings-manager-ROWQ5GC2.js → settings-manager-4GAINSJO.js} +3 -3
- package/{src-JIS3X4OU.js → src-YUVA6WCM.js} +253 -110
- package/src-YUVA6WCM.js.map +1 -0
- package/chunk-3N55WR7F.js.map +0 -1
- package/chunk-CNTL6NVU.js.map +0 -1
- package/chunk-HJUFIZ7H.js.map +0 -1
- package/chunk-OVV52N5F.js.map +0 -1
- package/chunk-YZU5FNXR.js +0 -43
- package/chunk-YZU5FNXR.js.map +0 -1
- package/src-JIS3X4OU.js.map +0 -1
- /package/{agent-manager-4HBMLHXU.js.map → agent-manager-BSPEFZKZ.js.map} +0 -0
- /package/{chat-VL6BIVO5.js.map → chat-SE5GIT4B.js.map} +0 -0
- /package/{companion-AUMA6RGX.js.map → companion-HEJHC3UR.js.map} +0 -0
- /package/{settings-manager-ROWQ5GC2.js.map → settings-manager-4GAINSJO.js.map} +0 -0
|
@@ -17,7 +17,6 @@ import {
|
|
|
17
17
|
apiKeyStore,
|
|
18
18
|
appVersion,
|
|
19
19
|
applyPersistedLanMode,
|
|
20
|
-
atomicWriteSecure,
|
|
21
20
|
auditService,
|
|
22
21
|
canEnvAction,
|
|
23
22
|
chatRouter,
|
|
@@ -51,7 +50,6 @@ import {
|
|
|
51
50
|
requireServiceAction,
|
|
52
51
|
resolveAgentCwd,
|
|
53
52
|
resolveConversationCwd,
|
|
54
|
-
resolveConversationRunDir,
|
|
55
53
|
resolveEffectiveAgentId,
|
|
56
54
|
resolveServiceVariables,
|
|
57
55
|
resolveWorkspaceCwd,
|
|
@@ -64,7 +62,7 @@ import {
|
|
|
64
62
|
soleAccountScope,
|
|
65
63
|
startCliSession,
|
|
66
64
|
vaultOfProject
|
|
67
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-BVBK2WII.js";
|
|
68
66
|
import {
|
|
69
67
|
resolveCliInvocation,
|
|
70
68
|
whichCommand
|
|
@@ -87,7 +85,7 @@ import {
|
|
|
87
85
|
stopClaudeTranscriptWatcher,
|
|
88
86
|
stopCodexTranscriptWatcher,
|
|
89
87
|
verifyJwt
|
|
90
|
-
} from "./chunk-
|
|
88
|
+
} from "./chunk-VNLIA5PV.js";
|
|
91
89
|
import "./chunk-MD3VW4HQ.js";
|
|
92
90
|
import {
|
|
93
91
|
agentManager,
|
|
@@ -125,11 +123,14 @@ import {
|
|
|
125
123
|
stableEncryptValue,
|
|
126
124
|
traefikManager,
|
|
127
125
|
unregisterInstance
|
|
128
|
-
} from "./chunk-
|
|
126
|
+
} from "./chunk-XTLQOYLT.js";
|
|
129
127
|
import {
|
|
130
128
|
settingsManager
|
|
131
|
-
} from "./chunk-
|
|
132
|
-
import
|
|
129
|
+
} from "./chunk-NIU3CN5A.js";
|
|
130
|
+
import {
|
|
131
|
+
atomicWriteSecure,
|
|
132
|
+
resolveConversationRunDir
|
|
133
|
+
} from "./chunk-GL7WA5K3.js";
|
|
133
134
|
import {
|
|
134
135
|
AGENT_LONG_FETCH_TIMEOUT,
|
|
135
136
|
AGENT_STOP_FETCH_TIMEOUT,
|
|
@@ -6579,11 +6580,61 @@ async function reconcileOrgCanary(orgId) {
|
|
|
6579
6580
|
}
|
|
6580
6581
|
|
|
6581
6582
|
// ../server/src/services/cloud-sync-bridge.ts
|
|
6582
|
-
import { randomUUID as
|
|
6583
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
6583
6584
|
import { mkdir as mkdir7, rm as rm3 } from "fs/promises";
|
|
6585
|
+
import * as Y2 from "yjs";
|
|
6586
|
+
|
|
6587
|
+
// ../server/src/services/sync-doc-cache.ts
|
|
6588
|
+
import { readFileSync, renameSync, rmSync, writeFileSync, mkdirSync } from "fs";
|
|
6589
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
6590
|
+
import { dirname as dirname4, join as join10 } from "path";
|
|
6591
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
6584
6592
|
import * as Y from "yjs";
|
|
6593
|
+
var FILE = "sync-doc.bin";
|
|
6594
|
+
function cachePath(orgId) {
|
|
6595
|
+
return join10(orgVaultRoot(orgId), FILE);
|
|
6596
|
+
}
|
|
6597
|
+
async function readSyncDoc(orgId) {
|
|
6598
|
+
try {
|
|
6599
|
+
return new Uint8Array(await readFile4(cachePath(orgId)));
|
|
6600
|
+
} catch {
|
|
6601
|
+
return null;
|
|
6602
|
+
}
|
|
6603
|
+
}
|
|
6604
|
+
function mergeWith(existing, state) {
|
|
6605
|
+
if (!existing) return state;
|
|
6606
|
+
try {
|
|
6607
|
+
return Y.mergeUpdates([existing, state]);
|
|
6608
|
+
} catch {
|
|
6609
|
+
return state;
|
|
6610
|
+
}
|
|
6611
|
+
}
|
|
6612
|
+
async function writeSyncDoc(orgId, state) {
|
|
6613
|
+
await atomicWriteSecure(cachePath(orgId), mergeWith(await readSyncDoc(orgId), state));
|
|
6614
|
+
}
|
|
6615
|
+
function writeSyncDocSync(orgId, state) {
|
|
6616
|
+
const path = cachePath(orgId);
|
|
6617
|
+
let existing = null;
|
|
6618
|
+
try {
|
|
6619
|
+
existing = new Uint8Array(readFileSync(path));
|
|
6620
|
+
} catch {
|
|
6621
|
+
}
|
|
6622
|
+
mkdirSync(dirname4(path), { recursive: true });
|
|
6623
|
+
const tmp = `${path}.${process.pid}.${randomUUID5()}.tmp`;
|
|
6624
|
+
try {
|
|
6625
|
+
writeFileSync(tmp, mergeWith(existing, state), { mode: 384 });
|
|
6626
|
+
renameSync(tmp, path);
|
|
6627
|
+
} catch (err) {
|
|
6628
|
+
rmSync(tmp, { force: true });
|
|
6629
|
+
throw err;
|
|
6630
|
+
}
|
|
6631
|
+
}
|
|
6632
|
+
|
|
6633
|
+
// ../server/src/services/cloud-sync-bridge.ts
|
|
6585
6634
|
var LOCAL_ORIGIN = "local-bridge";
|
|
6586
6635
|
var REMOTE_ORIGIN = "remote";
|
|
6636
|
+
var CACHE_ORIGIN = "cache";
|
|
6637
|
+
var PERSIST_DEBOUNCE_MS = 1e3;
|
|
6587
6638
|
var RECONNECT_DELAY_MS = 3e3;
|
|
6588
6639
|
var UNAUTHENTICATED_RETRY_MS = 5 * 6e4;
|
|
6589
6640
|
var OUTDATED_RETRY_MS = 30 * 6e4;
|
|
@@ -6616,12 +6667,12 @@ var ProjectHeldElsewhereError = class extends Error {
|
|
|
6616
6667
|
code = "PROJECT_HELD_ELSEWHERE";
|
|
6617
6668
|
};
|
|
6618
6669
|
var OrgSyncConnection = class {
|
|
6619
|
-
doc = new
|
|
6670
|
+
doc = new Y2.Doc();
|
|
6620
6671
|
projects = getCollection(this.doc, "projects");
|
|
6621
6672
|
services = getCollection(this.doc, "services");
|
|
6622
6673
|
environments = getCollection(this.doc, "environments");
|
|
6623
6674
|
logParsers = getCollection(this.doc, PARSERS);
|
|
6624
|
-
conn =
|
|
6675
|
+
conn = randomUUID6();
|
|
6625
6676
|
link;
|
|
6626
6677
|
stopped = false;
|
|
6627
6678
|
initializing = true;
|
|
@@ -6657,6 +6708,31 @@ var OrgSyncConnection = class {
|
|
|
6657
6708
|
* creating a project sees it appear on their teammates' machines.
|
|
6658
6709
|
*/
|
|
6659
6710
|
initialDocApplied = false;
|
|
6711
|
+
/**
|
|
6712
|
+
* Whether local state has been written into the doc.
|
|
6713
|
+
*
|
|
6714
|
+
* Never before the doc holds the known history — reloaded from disk, or
|
|
6715
|
+
* received from the cloud. Written into an empty doc, local state is
|
|
6716
|
+
* concurrent with every past write and loses to some of them at random: an
|
|
6717
|
+
* offline edit reverted, a service on disk erased by an older deletion.
|
|
6718
|
+
*/
|
|
6719
|
+
seeded = false;
|
|
6720
|
+
/** Store applications started by remote events and not finished yet. */
|
|
6721
|
+
applying = /* @__PURE__ */ new Set();
|
|
6722
|
+
/**
|
|
6723
|
+
* When each entity was last changed by a remote update (`collection:id` → tick).
|
|
6724
|
+
*
|
|
6725
|
+
* Reconciliation reads the stores, waits, then writes what it read. A remote
|
|
6726
|
+
* change landing in between makes that read stale, and writing it would erase
|
|
6727
|
+
* the value that just arrived — for every member. Entities touched since the
|
|
6728
|
+
* read began are left alone: their application brings the disk up to date,
|
|
6729
|
+
* and the reconciliation it triggers starts from there.
|
|
6730
|
+
*/
|
|
6731
|
+
remoteTouch = /* @__PURE__ */ new Map();
|
|
6732
|
+
remoteClock = 0;
|
|
6733
|
+
persistTimer = null;
|
|
6734
|
+
/** The cache write under way, so stopping can wait for it to land. */
|
|
6735
|
+
persisting = Promise.resolve();
|
|
6660
6736
|
unsubscribes = [];
|
|
6661
6737
|
onSaved = () => void this.reconcileLocalToDoc();
|
|
6662
6738
|
constructor(link) {
|
|
@@ -6686,29 +6762,79 @@ var OrgSyncConnection = class {
|
|
|
6686
6762
|
if (txn.origin !== REMOTE_ORIGIN) return;
|
|
6687
6763
|
const isInitial = !this.initialDocApplied;
|
|
6688
6764
|
if (name === "projects") this.initialDocApplied = true;
|
|
6689
|
-
|
|
6765
|
+
this.track(this.applyDocEventsToStore(name, events, isInitial));
|
|
6690
6766
|
});
|
|
6691
6767
|
}
|
|
6692
6768
|
this.logParsers.observeDeep((events, txn) => {
|
|
6693
6769
|
if (txn.origin !== REMOTE_ORIGIN) return;
|
|
6694
|
-
|
|
6770
|
+
this.track(this.applyParserEventsToStore(events));
|
|
6695
6771
|
});
|
|
6696
6772
|
projectStore.events.on("saved", this.onSaved);
|
|
6697
6773
|
this.unsubscribes.push(serviceStore.onChange(this.onSaved));
|
|
6698
6774
|
this.unsubscribes.push(environmentStore.onChange(this.onSaved));
|
|
6699
6775
|
this.unsubscribes.push(logParserStore.onLocalChange(this.onSaved));
|
|
6776
|
+
const cached = await readSyncDoc(this.link.orgId);
|
|
6777
|
+
if (cached) {
|
|
6778
|
+
try {
|
|
6779
|
+
Y2.applyUpdate(this.doc, cached, CACHE_ORIGIN);
|
|
6780
|
+
this.initialDocApplied = true;
|
|
6781
|
+
} catch (err) {
|
|
6782
|
+
console.error("[cloud-sync] unreadable sync cache for org %s, ignored:", this.link.orgId, err.message);
|
|
6783
|
+
}
|
|
6784
|
+
}
|
|
6785
|
+
this.doc.on("update", () => this.schedulePersist());
|
|
6786
|
+
if (cached && this.initialDocApplied) await this.seed();
|
|
6787
|
+
void this.streamLoop();
|
|
6788
|
+
}
|
|
6789
|
+
/** Write local state on top of the known history, then owe it to the cloud. */
|
|
6790
|
+
async seed() {
|
|
6791
|
+
this.seeded = true;
|
|
6700
6792
|
await this.reconcileLocalToDoc();
|
|
6701
6793
|
this.initializing = false;
|
|
6702
6794
|
this.needsPush = true;
|
|
6703
|
-
void this.streamLoop();
|
|
6704
6795
|
}
|
|
6796
|
+
track(work) {
|
|
6797
|
+
this.applying.add(work);
|
|
6798
|
+
void work.finally(() => this.applying.delete(work));
|
|
6799
|
+
}
|
|
6800
|
+
async settleApplying() {
|
|
6801
|
+
while (this.applying.size > 0) await Promise.allSettled(this.applying);
|
|
6802
|
+
}
|
|
6803
|
+
schedulePersist() {
|
|
6804
|
+
if (this.stopped || this.persistTimer) return;
|
|
6805
|
+
this.persistTimer = setTimeout(() => {
|
|
6806
|
+
this.persistTimer = null;
|
|
6807
|
+
this.persisting = this.persisting.then(() => this.persist());
|
|
6808
|
+
}, PERSIST_DEBOUNCE_MS);
|
|
6809
|
+
}
|
|
6810
|
+
async persist() {
|
|
6811
|
+
if (this.stopped) return;
|
|
6812
|
+
try {
|
|
6813
|
+
await writeSyncDoc(this.link.orgId, Y2.encodeStateAsUpdate(this.doc));
|
|
6814
|
+
} catch (err) {
|
|
6815
|
+
console.error("[cloud-sync] could not save sync cache for org %s:", this.link.orgId, err.message);
|
|
6816
|
+
}
|
|
6817
|
+
}
|
|
6818
|
+
/** Resolves once any cache write already under way has landed. */
|
|
6705
6819
|
stop() {
|
|
6706
6820
|
this.stopped = true;
|
|
6707
6821
|
this.state = "stopped";
|
|
6708
6822
|
projectStore.events.off("saved", this.onSaved);
|
|
6709
6823
|
for (const off of this.unsubscribes.splice(0)) off();
|
|
6710
6824
|
this.abort?.abort();
|
|
6825
|
+
if (this.persistTimer) {
|
|
6826
|
+
clearTimeout(this.persistTimer);
|
|
6827
|
+
this.persistTimer = null;
|
|
6828
|
+
}
|
|
6829
|
+
if (this.seeded) {
|
|
6830
|
+
try {
|
|
6831
|
+
writeSyncDocSync(this.link.orgId, Y2.encodeStateAsUpdate(this.doc));
|
|
6832
|
+
} catch (err) {
|
|
6833
|
+
console.error("[cloud-sync] could not save sync cache for org %s:", this.link.orgId, err.message);
|
|
6834
|
+
}
|
|
6835
|
+
}
|
|
6711
6836
|
this.doc.destroy();
|
|
6837
|
+
return this.persisting;
|
|
6712
6838
|
}
|
|
6713
6839
|
// ---- Transport -------------------------------------------------------
|
|
6714
6840
|
/**
|
|
@@ -6786,7 +6912,7 @@ var OrgSyncConnection = class {
|
|
|
6786
6912
|
if (!svRes.ok) return;
|
|
6787
6913
|
const { sv } = await svRes.json();
|
|
6788
6914
|
const cloudSv = new Uint8Array(Buffer.from(sv, "base64"));
|
|
6789
|
-
const diff =
|
|
6915
|
+
const diff = Y2.encodeStateAsUpdate(this.doc, cloudSv);
|
|
6790
6916
|
await this.pushUpdate(diff);
|
|
6791
6917
|
} catch (err) {
|
|
6792
6918
|
if (err instanceof SyncAuthError || err instanceof SyncOutdatedError) throw err;
|
|
@@ -6848,7 +6974,7 @@ var OrgSyncConnection = class {
|
|
|
6848
6974
|
}
|
|
6849
6975
|
async streamOnce() {
|
|
6850
6976
|
this.abort = new AbortController();
|
|
6851
|
-
const since = Buffer.from(
|
|
6977
|
+
const since = Buffer.from(Y2.encodeStateVector(this.doc)).toString("base64");
|
|
6852
6978
|
const res = await fetch(this.url(`/stream?conn=${this.conn}&since=${encodeURIComponent(since)}`), {
|
|
6853
6979
|
headers: { Authorization: await this.authHeader(), [APP_VERSION_HEADER]: appVersion },
|
|
6854
6980
|
signal: this.abort.signal
|
|
@@ -6872,8 +6998,17 @@ var OrgSyncConnection = class {
|
|
|
6872
6998
|
try {
|
|
6873
6999
|
const payload = JSON.parse(line.slice(6));
|
|
6874
7000
|
const update = new Uint8Array(Buffer.from(payload.update, "base64"));
|
|
6875
|
-
|
|
7001
|
+
Y2.applyUpdate(this.doc, update, REMOTE_ORIGIN);
|
|
6876
7002
|
} catch {
|
|
7003
|
+
continue;
|
|
7004
|
+
}
|
|
7005
|
+
if (!this.seeded) {
|
|
7006
|
+
this.initialDocApplied = true;
|
|
7007
|
+
await this.settleApplying();
|
|
7008
|
+
if (this.stopped) return;
|
|
7009
|
+
await this.seed();
|
|
7010
|
+
await this.initialPush();
|
|
7011
|
+
this.needsPush = false;
|
|
6877
7012
|
}
|
|
6878
7013
|
}
|
|
6879
7014
|
}
|
|
@@ -7018,6 +7153,7 @@ var OrgSyncConnection = class {
|
|
|
7018
7153
|
if (typeof topKey === "string") affected.add(topKey);
|
|
7019
7154
|
}
|
|
7020
7155
|
}
|
|
7156
|
+
for (const id of [...deleted, ...affected]) this.remoteTouch.set(`${name}:${id}`, ++this.remoteClock);
|
|
7021
7157
|
for (const id of deleted) {
|
|
7022
7158
|
if (!this.isTrackedForDeletion(name, id)) continue;
|
|
7023
7159
|
await this.deleteLocally(name, id);
|
|
@@ -7170,7 +7306,9 @@ var OrgSyncConnection = class {
|
|
|
7170
7306
|
* propagate — otherwise a service could never be removed.
|
|
7171
7307
|
*/
|
|
7172
7308
|
async reconcileLocalToDoc() {
|
|
7173
|
-
if (this.stopped || this.pulling) return;
|
|
7309
|
+
if (this.stopped || this.pulling || !this.seeded) return;
|
|
7310
|
+
const readAt = this.remoteClock;
|
|
7311
|
+
const touchedSinceRead = (name, id) => (this.remoteTouch.get(`${name}:${id}`) ?? 0) > readAt;
|
|
7174
7312
|
const projects = (await projectStore.listDiskFormByOrg(this.link.orgId)).filter((p) => !this.refusalFor(p.id));
|
|
7175
7313
|
const projectIds = projects.map((p) => p.id);
|
|
7176
7314
|
const serviceIds = [...new Set(projects.flatMap((p) => p.serviceIds ?? []))];
|
|
@@ -7188,10 +7326,12 @@ var OrgSyncConnection = class {
|
|
|
7188
7326
|
const collection = this.collection(name);
|
|
7189
7327
|
const entities = local[name];
|
|
7190
7328
|
const ids = new Set(entities.map((e) => e.id));
|
|
7191
|
-
for (const entity of entities)
|
|
7329
|
+
for (const entity of entities) {
|
|
7330
|
+
if (!touchedSinceRead(name, entity.id)) writeEntity(collection, entity.id, entity);
|
|
7331
|
+
}
|
|
7192
7332
|
if (name === "projects") continue;
|
|
7193
7333
|
for (const id of Array.from(collection.keys())) {
|
|
7194
|
-
if (ids.has(id)) continue;
|
|
7334
|
+
if (ids.has(id) || touchedSinceRead(name, id)) continue;
|
|
7195
7335
|
if (this.belongsToOwnedProject(name, id, ownedProjectIds)) collection.delete(id);
|
|
7196
7336
|
}
|
|
7197
7337
|
}
|
|
@@ -7380,21 +7520,24 @@ var CloudSyncBridge = class {
|
|
|
7380
7520
|
disconnect(orgId) {
|
|
7381
7521
|
const existing = this.connections.get(orgId);
|
|
7382
7522
|
if (existing) {
|
|
7383
|
-
existing.stop();
|
|
7523
|
+
void existing.stop();
|
|
7384
7524
|
this.connections.delete(orgId);
|
|
7385
7525
|
}
|
|
7386
7526
|
}
|
|
7527
|
+
/** Stops at once; the promise only says when pending cache writes have landed. */
|
|
7387
7528
|
stopAll() {
|
|
7388
|
-
|
|
7529
|
+
const stopping = [...this.connections.values()].map((conn) => conn.stop());
|
|
7389
7530
|
this.connections.clear();
|
|
7390
7531
|
this.keyMismatch.clear();
|
|
7532
|
+
return Promise.all(stopping).then(() => {
|
|
7533
|
+
});
|
|
7391
7534
|
}
|
|
7392
7535
|
};
|
|
7393
7536
|
var cloudSyncBridge = new CloudSyncBridge();
|
|
7394
7537
|
|
|
7395
7538
|
// ../server/src/services/key-adoption.ts
|
|
7396
|
-
import { readdir as readdir3, readFile as
|
|
7397
|
-
import { join as
|
|
7539
|
+
import { readdir as readdir3, readFile as readFile5, writeFile as writeFile6, mkdir as mkdir8, copyFile, rename as rename4, stat as stat5 } from "fs/promises";
|
|
7540
|
+
import { join as join11 } from "path";
|
|
7398
7541
|
import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes2 } from "crypto";
|
|
7399
7542
|
var ALGORITHM = "aes-256-gcm";
|
|
7400
7543
|
function isAgentTriplet(value) {
|
|
@@ -7474,10 +7617,10 @@ async function adoptOrgKey(orgId, newKey, masterPassword, now) {
|
|
|
7474
7617
|
const touchedRoots = /* @__PURE__ */ new Set();
|
|
7475
7618
|
for (const vaultRoot of await rootsOfOrg(orgId)) {
|
|
7476
7619
|
for (const name of await jsonFilesIn(vaultRoot)) {
|
|
7477
|
-
const path =
|
|
7620
|
+
const path = join11(vaultRoot, name);
|
|
7478
7621
|
let parsed;
|
|
7479
7622
|
try {
|
|
7480
|
-
parsed = JSON.parse(await
|
|
7623
|
+
parsed = JSON.parse(await readFile5(path, "utf-8"));
|
|
7481
7624
|
} catch {
|
|
7482
7625
|
continue;
|
|
7483
7626
|
}
|
|
@@ -7491,14 +7634,14 @@ async function adoptOrgKey(orgId, newKey, masterPassword, now) {
|
|
|
7491
7634
|
const stamp = now.toISOString().replace(/[:.]/g, "-").substring(0, 19);
|
|
7492
7635
|
const backups = [];
|
|
7493
7636
|
for (const vaultRoot of touchedRoots) {
|
|
7494
|
-
const backupDir =
|
|
7637
|
+
const backupDir = join11(vaultRoot, `backup-key-${stamp}`);
|
|
7495
7638
|
await mkdir8(backupDir, { recursive: true });
|
|
7496
7639
|
for (const name of await jsonFilesIn(vaultRoot)) {
|
|
7497
|
-
await copyFile(
|
|
7640
|
+
await copyFile(join11(vaultRoot, name), join11(backupDir, name));
|
|
7498
7641
|
}
|
|
7499
7642
|
for (const name of [".encryption.key.enc", ".runeya-verify"]) {
|
|
7500
|
-
if (await exists(
|
|
7501
|
-
await copyFile(
|
|
7643
|
+
if (await exists(join11(vaultRoot, name))) {
|
|
7644
|
+
await copyFile(join11(vaultRoot, name), join11(backupDir, name));
|
|
7502
7645
|
}
|
|
7503
7646
|
}
|
|
7504
7647
|
backups.push(backupDir);
|
|
@@ -7963,13 +8106,13 @@ var cloudSyncRouter = router({
|
|
|
7963
8106
|
// ../server/src/trpc/routers/filesystem.ts
|
|
7964
8107
|
import { readdir as readdir4, stat as stat6 } from "fs/promises";
|
|
7965
8108
|
import { homedir as homedir3 } from "os";
|
|
7966
|
-
import { isAbsolute, join as
|
|
8109
|
+
import { isAbsolute, join as join12, resolve as resolve2, dirname as dirname5, basename } from "path";
|
|
7967
8110
|
import { z as z24 } from "zod";
|
|
7968
8111
|
var MAX_ENTRIES2 = 500;
|
|
7969
8112
|
var PATH_SCHEMA = z24.string().min(1).max(4096);
|
|
7970
8113
|
function safeResolve(input) {
|
|
7971
8114
|
if (input.includes("\0")) throw new Error("Chemin invalide");
|
|
7972
|
-
const expanded = input.startsWith("~") ?
|
|
8115
|
+
const expanded = input.startsWith("~") ? join12(homedir3(), input.slice(1)) : input;
|
|
7973
8116
|
if (!isAbsolute(expanded)) throw new Error("Le chemin doit \xEAtre absolu");
|
|
7974
8117
|
return resolve2(expanded);
|
|
7975
8118
|
}
|
|
@@ -8005,13 +8148,13 @@ var filesystemRouter = router({
|
|
|
8005
8148
|
const truncated = names.length > MAX_ENTRIES2;
|
|
8006
8149
|
const entries2 = [];
|
|
8007
8150
|
for (const name of names.slice(0, MAX_ENTRIES2)) {
|
|
8008
|
-
const path =
|
|
8151
|
+
const path = join12(dir, name);
|
|
8009
8152
|
entries2.push({ name, path, hasRuneyaProject: await holdsRuneyaProject(path) });
|
|
8010
8153
|
}
|
|
8011
8154
|
return {
|
|
8012
8155
|
path: dir,
|
|
8013
8156
|
// Null at the filesystem root, which is what stops "up" from looping.
|
|
8014
|
-
parent:
|
|
8157
|
+
parent: dirname5(dir) === dir ? null : dirname5(dir),
|
|
8015
8158
|
name: basename(dir) || dir,
|
|
8016
8159
|
entries: entries2,
|
|
8017
8160
|
truncated,
|
|
@@ -8266,8 +8409,8 @@ async function ensureFilePermissions() {
|
|
|
8266
8409
|
}
|
|
8267
8410
|
|
|
8268
8411
|
// ../server/src/services/vault-migration.ts
|
|
8269
|
-
import { readdir as readdir5, readFile as
|
|
8270
|
-
import { join as
|
|
8412
|
+
import { readdir as readdir5, readFile as readFile6, writeFile as writeFile7, mkdir as mkdir9, copyFile as copyFile2, unlink, rename as rename5, stat as stat8 } from "fs/promises";
|
|
8413
|
+
import { join as join13 } from "path";
|
|
8271
8414
|
var KEY_FILES = [".encryption.key.enc", ".runeya-verify"];
|
|
8272
8415
|
var MACHINE_FILES = [
|
|
8273
8416
|
"agents.json",
|
|
@@ -8297,17 +8440,17 @@ async function openLegacyVault(legacyRoot, masterPassword) {
|
|
|
8297
8440
|
}
|
|
8298
8441
|
async function migrateLegacyVault(legacyRoot, machineRootDir, legacyKey, machineKey, now) {
|
|
8299
8442
|
const stamp = now.toISOString().replace(/[:.]/g, "-").substring(0, 19);
|
|
8300
|
-
const backupDir =
|
|
8443
|
+
const backupDir = join13(legacyRoot, `backup-${stamp}`);
|
|
8301
8444
|
await mkdir9(backupDir, { recursive: true });
|
|
8302
8445
|
const jsonFiles = await vaultJsonFiles(legacyRoot);
|
|
8303
8446
|
for (const name of [...jsonFiles, ...KEY_FILES]) {
|
|
8304
|
-
if (await exists2(
|
|
8305
|
-
await copyFile2(
|
|
8447
|
+
if (await exists2(join13(legacyRoot, name))) {
|
|
8448
|
+
await copyFile2(join13(legacyRoot, name), join13(backupDir, name));
|
|
8306
8449
|
}
|
|
8307
8450
|
}
|
|
8308
8451
|
const rekeyed = [];
|
|
8309
8452
|
for (const name of jsonFiles) {
|
|
8310
|
-
const raw = await
|
|
8453
|
+
const raw = await readFile6(join13(legacyRoot, name), "utf-8");
|
|
8311
8454
|
let parsed;
|
|
8312
8455
|
try {
|
|
8313
8456
|
parsed = JSON.parse(raw);
|
|
@@ -8317,13 +8460,13 @@ async function migrateLegacyVault(legacyRoot, machineRootDir, legacyKey, machine
|
|
|
8317
8460
|
const counter = { n: 0 };
|
|
8318
8461
|
const converted = rekeyValue(parsed, legacyKey, machineKey, counter);
|
|
8319
8462
|
if (counter.n === 0) continue;
|
|
8320
|
-
const tmp =
|
|
8463
|
+
const tmp = join13(legacyRoot, `${name}.tmp`);
|
|
8321
8464
|
await writeFile7(tmp, JSON.stringify(converted, null, 2), "utf-8");
|
|
8322
|
-
await rename5(tmp,
|
|
8465
|
+
await rename5(tmp, join13(legacyRoot, name));
|
|
8323
8466
|
rekeyed.push({ file: name, values: counter.n });
|
|
8324
8467
|
}
|
|
8325
8468
|
for (const { file, values } of rekeyed) {
|
|
8326
|
-
const parsed = JSON.parse(await
|
|
8469
|
+
const parsed = JSON.parse(await readFile6(join13(legacyRoot, file), "utf-8"));
|
|
8327
8470
|
const check = { n: 0 };
|
|
8328
8471
|
rekeyValue(parsed, machineKey, machineKey, check);
|
|
8329
8472
|
if (check.n !== values) {
|
|
@@ -8336,9 +8479,9 @@ async function migrateLegacyVault(legacyRoot, machineRootDir, legacyKey, machine
|
|
|
8336
8479
|
const moved = [];
|
|
8337
8480
|
const skipped = [];
|
|
8338
8481
|
for (const name of MACHINE_FILES) {
|
|
8339
|
-
const from =
|
|
8482
|
+
const from = join13(legacyRoot, name);
|
|
8340
8483
|
if (!await exists2(from)) continue;
|
|
8341
|
-
const to =
|
|
8484
|
+
const to = join13(machineRootDir, name);
|
|
8342
8485
|
if (await exists2(to)) {
|
|
8343
8486
|
skipped.push(name);
|
|
8344
8487
|
continue;
|
|
@@ -8348,15 +8491,15 @@ async function migrateLegacyVault(legacyRoot, machineRootDir, legacyKey, machine
|
|
|
8348
8491
|
moved.push(name);
|
|
8349
8492
|
}
|
|
8350
8493
|
for (const name of KEY_FILES) {
|
|
8351
|
-
const path =
|
|
8494
|
+
const path = join13(legacyRoot, name);
|
|
8352
8495
|
if (await exists2(path)) await unlink(path);
|
|
8353
8496
|
}
|
|
8354
8497
|
return { backupDir, rekeyed, moved, skipped };
|
|
8355
8498
|
}
|
|
8356
8499
|
|
|
8357
8500
|
// ../server/src/services/settings-migration.ts
|
|
8358
|
-
import { readFile as
|
|
8359
|
-
import { join as
|
|
8501
|
+
import { readFile as readFile7, writeFile as writeFile8, rename as rename6, unlink as unlink2, mkdir as mkdir10, chmod as chmod4, stat as stat9 } from "fs/promises";
|
|
8502
|
+
import { join as join14 } from "path";
|
|
8360
8503
|
var SETTINGS_FILE = "settings.json";
|
|
8361
8504
|
var SETTINGS_PRIVATE_FILE = "settings.private.json";
|
|
8362
8505
|
async function exists3(path) {
|
|
@@ -8370,8 +8513,8 @@ async function legacySource(filename) {
|
|
|
8370
8513
|
}
|
|
8371
8514
|
async function moveInto(root, filename, from) {
|
|
8372
8515
|
await mkdir10(root, { recursive: true });
|
|
8373
|
-
const to =
|
|
8374
|
-
const contents = await
|
|
8516
|
+
const to = join14(root, filename);
|
|
8517
|
+
const contents = await readFile7(from, "utf-8");
|
|
8375
8518
|
const tmp = to + ".tmp";
|
|
8376
8519
|
await writeFile8(tmp, contents, "utf-8");
|
|
8377
8520
|
await rename6(tmp, to);
|
|
@@ -8395,7 +8538,7 @@ async function migrateSettingsIntoVaults() {
|
|
|
8395
8538
|
const orgId = orgs[0];
|
|
8396
8539
|
const root = orgVaultRoot(orgId);
|
|
8397
8540
|
for (const { filename, from } of sources) {
|
|
8398
|
-
if (await exists3(
|
|
8541
|
+
if (await exists3(join14(root, filename))) continue;
|
|
8399
8542
|
await moveInto(root, filename, from);
|
|
8400
8543
|
report.files.push(filename);
|
|
8401
8544
|
}
|
|
@@ -8409,16 +8552,16 @@ async function migrateSettingsIntoVaults() {
|
|
|
8409
8552
|
// ../server/src/migrations/migrate-from-legacy.ts
|
|
8410
8553
|
import { createRequire } from "module";
|
|
8411
8554
|
import { randomBytes as randomBytes3, createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3 } from "crypto";
|
|
8412
|
-
import { randomUUID as
|
|
8555
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
8413
8556
|
import {
|
|
8414
|
-
readFile as
|
|
8557
|
+
readFile as readFile8,
|
|
8415
8558
|
writeFile as writeFile9,
|
|
8416
8559
|
rename as rename7,
|
|
8417
8560
|
mkdir as mkdir11,
|
|
8418
8561
|
access as access2,
|
|
8419
8562
|
readdir as readdir6
|
|
8420
8563
|
} from "fs/promises";
|
|
8421
|
-
import { join as
|
|
8564
|
+
import { join as join15, dirname as dirname6 } from "path";
|
|
8422
8565
|
var _require = createRequire(import.meta.url);
|
|
8423
8566
|
var PARSER_ID_MAP = {
|
|
8424
8567
|
"stack-monitor-parser-jsons": "native:json",
|
|
@@ -8535,7 +8678,7 @@ async function getSodium() {
|
|
|
8535
8678
|
return _sodium;
|
|
8536
8679
|
}
|
|
8537
8680
|
async function decryptLegacyFile(filePath, key, sodium) {
|
|
8538
|
-
const raw = (await
|
|
8681
|
+
const raw = (await readFile8(filePath, "utf-8")).trim();
|
|
8539
8682
|
if (!raw || raw === "[]" || raw === "{}") {
|
|
8540
8683
|
try {
|
|
8541
8684
|
return JSON.parse(raw);
|
|
@@ -8560,7 +8703,7 @@ async function atomicWrite(path, data) {
|
|
|
8560
8703
|
}
|
|
8561
8704
|
async function runLegacyMigration(dataDir) {
|
|
8562
8705
|
const legacyRoot = env.DATA_DIR;
|
|
8563
|
-
const legacyKeyPath =
|
|
8706
|
+
const legacyKeyPath = join15(legacyRoot, "dbs", "encryption-key.json");
|
|
8564
8707
|
try {
|
|
8565
8708
|
await access2(legacyKeyPath);
|
|
8566
8709
|
} catch {
|
|
@@ -8571,17 +8714,17 @@ async function runLegacyMigration(dataDir) {
|
|
|
8571
8714
|
const legacyTmp = `${legacyRoot}-tmp`;
|
|
8572
8715
|
await rename7(legacyRoot, legacyTmp);
|
|
8573
8716
|
await mkdir11(dataDir, { recursive: true });
|
|
8574
|
-
const legacyOld =
|
|
8717
|
+
const legacyOld = join15(dataDir, `backup-${timestamp}`);
|
|
8575
8718
|
await rename7(legacyTmp, legacyOld);
|
|
8576
8719
|
console.log(`[legacy-migration] Legacy data backed up to ${legacyOld}`);
|
|
8577
|
-
const keyJson = JSON.parse(await
|
|
8720
|
+
const keyJson = JSON.parse(await readFile8(join15(legacyOld, "dbs", "encryption-key.json"), "utf-8"));
|
|
8578
8721
|
const sodium = await getSodium();
|
|
8579
8722
|
const sodiumKey = sodium.from_base64(keyJson.encryptionKey);
|
|
8580
8723
|
const keyBuffer = Buffer.from(sodiumKey);
|
|
8581
8724
|
const runyeaKeyHex = keyBuffer.toString("hex");
|
|
8582
8725
|
await setEncryptionKey(runyeaKeyHex);
|
|
8583
8726
|
console.log("[legacy-migration] Encryption key loaded in memory (temporary)");
|
|
8584
|
-
const dbsDir =
|
|
8727
|
+
const dbsDir = join15(legacyOld, "dbs");
|
|
8585
8728
|
async function readEncrypted(filePath) {
|
|
8586
8729
|
try {
|
|
8587
8730
|
return await decryptLegacyFile(filePath, sodiumKey, sodium);
|
|
@@ -8590,29 +8733,29 @@ async function runLegacyMigration(dataDir) {
|
|
|
8590
8733
|
return null;
|
|
8591
8734
|
}
|
|
8592
8735
|
}
|
|
8593
|
-
const envsDir =
|
|
8736
|
+
const envsDir = join15(dbsDir, "envs");
|
|
8594
8737
|
const envFiles = (await readdir6(envsDir).catch(() => [])).filter((f) => f.endsWith(".encrypted.json"));
|
|
8595
8738
|
const legacyEnvs = {};
|
|
8596
8739
|
for (const file of envFiles) {
|
|
8597
8740
|
const name = file.replace(".encrypted.json", "");
|
|
8598
|
-
legacyEnvs[name] = await readEncrypted(
|
|
8741
|
+
legacyEnvs[name] = await readEncrypted(join15(envsDir, file));
|
|
8599
8742
|
}
|
|
8600
|
-
const servicesDir =
|
|
8743
|
+
const servicesDir = join15(dbsDir, "services");
|
|
8601
8744
|
const serviceFiles = (await readdir6(servicesDir).catch(() => [])).filter((f) => f.endsWith(".encrypted.json"));
|
|
8602
8745
|
const legacyServices = {};
|
|
8603
8746
|
for (const file of serviceFiles) {
|
|
8604
8747
|
const name = file.replace(".encrypted.json", "");
|
|
8605
8748
|
if (!name) continue;
|
|
8606
|
-
const data = await readEncrypted(
|
|
8749
|
+
const data = await readEncrypted(join15(servicesDir, file));
|
|
8607
8750
|
if (data?.label) legacyServices[name] = data;
|
|
8608
8751
|
}
|
|
8609
|
-
const overridesDir =
|
|
8752
|
+
const overridesDir = join15(dbsDir, "overrides");
|
|
8610
8753
|
const overrideFiles = (await readdir6(overridesDir).catch(() => [])).filter((f) => f.endsWith(".encrypted.json"));
|
|
8611
8754
|
const legacyServiceOverrides = {};
|
|
8612
8755
|
const legacyEnvOverrides = {};
|
|
8613
8756
|
for (const file of overrideFiles) {
|
|
8614
8757
|
const baseName = file.replace(".encrypted.json", "");
|
|
8615
|
-
const data = await readEncrypted(
|
|
8758
|
+
const data = await readEncrypted(join15(overridesDir, file));
|
|
8616
8759
|
if (!data) continue;
|
|
8617
8760
|
if (baseName.endsWith("-envs")) {
|
|
8618
8761
|
legacyServiceOverrides[baseName.slice(0, -5)] = data;
|
|
@@ -8620,18 +8763,18 @@ async function runLegacyMigration(dataDir) {
|
|
|
8620
8763
|
legacyEnvOverrides[baseName.slice(0, -12)] = data;
|
|
8621
8764
|
}
|
|
8622
8765
|
}
|
|
8623
|
-
const parsersDir =
|
|
8766
|
+
const parsersDir = join15(dbsDir, "parsers");
|
|
8624
8767
|
const parserFiles = (await readdir6(parsersDir).catch(() => [])).filter((f) => f.endsWith(".encrypted.json"));
|
|
8625
8768
|
const legacyParsers = [];
|
|
8626
8769
|
for (const file of parserFiles) {
|
|
8627
|
-
const data = await readEncrypted(
|
|
8770
|
+
const data = await readEncrypted(join15(parsersDir, file));
|
|
8628
8771
|
if (data?.id) legacyParsers.push(data);
|
|
8629
8772
|
}
|
|
8630
|
-
const projectMonoId =
|
|
8773
|
+
const projectMonoId = randomUUID7();
|
|
8631
8774
|
const envIdMap = {};
|
|
8632
8775
|
const labelToKey = {};
|
|
8633
8776
|
for (const [name, legacyEnv] of Object.entries(legacyEnvs)) {
|
|
8634
|
-
envIdMap[name] =
|
|
8777
|
+
envIdMap[name] = randomUUID7();
|
|
8635
8778
|
if (legacyEnv?.label) labelToKey[legacyEnv.label] = name;
|
|
8636
8779
|
}
|
|
8637
8780
|
const runeEnvs = [];
|
|
@@ -8656,7 +8799,7 @@ async function runLegacyMigration(dataDir) {
|
|
|
8656
8799
|
if (hasInvalidInterpolation(value)) continue;
|
|
8657
8800
|
const cleaned = cleanVarKey(key);
|
|
8658
8801
|
if (inheritedVars[cleaned] === value) continue;
|
|
8659
|
-
const varId =
|
|
8802
|
+
const varId = randomUUID7();
|
|
8660
8803
|
variables[varId] = makeVariable(cleaned, value);
|
|
8661
8804
|
varIdLookup.set(`${envIdMap[name]}:${cleaned}`, varId);
|
|
8662
8805
|
}
|
|
@@ -8677,7 +8820,7 @@ async function runLegacyMigration(dataDir) {
|
|
|
8677
8820
|
const serviceIdMap = {};
|
|
8678
8821
|
const runeServices = [];
|
|
8679
8822
|
for (const [name, legacy] of Object.entries(legacyServices)) {
|
|
8680
|
-
const id =
|
|
8823
|
+
const id = randomUUID7();
|
|
8681
8824
|
serviceIdMap[name] = id;
|
|
8682
8825
|
const rootPath = legacy.rootPath || "";
|
|
8683
8826
|
const rootPathCwd = rootPath && rootPath !== "." ? rootPath : "";
|
|
@@ -8686,7 +8829,7 @@ async function runLegacyMigration(dataDir) {
|
|
|
8686
8829
|
const parts = [cmd.spawnCmd, ...cmd.spawnArgs || []].filter(Boolean);
|
|
8687
8830
|
if (!parts.length) continue;
|
|
8688
8831
|
commands.push({
|
|
8689
|
-
id: cmd.id ||
|
|
8832
|
+
id: cmd.id || randomUUID7(),
|
|
8690
8833
|
label: "Launch",
|
|
8691
8834
|
command: parts.join(" "),
|
|
8692
8835
|
cwd: cmd.spawnOptions?.cwd || "",
|
|
@@ -8747,7 +8890,7 @@ async function runLegacyMigration(dataDir) {
|
|
|
8747
8890
|
const legacyBootstrapCmds = container.bootstrap?.commands || [];
|
|
8748
8891
|
if (legacyBootstrapCmds.length > 0) {
|
|
8749
8892
|
dockerConfig.bootstrapCommands = legacyBootstrapCmds.filter((bs) => bs.cmd || bs.entrypoint).map((bs, idx) => ({
|
|
8750
|
-
id: bs.id ||
|
|
8893
|
+
id: bs.id || randomUUID7(),
|
|
8751
8894
|
label: bs.label || `Bootstrap ${idx + 1}`,
|
|
8752
8895
|
command: bs.cmd || "",
|
|
8753
8896
|
...bs.entrypoint ? { entrypoint: bs.entrypoint } : {},
|
|
@@ -8795,7 +8938,7 @@ async function runLegacyMigration(dataDir) {
|
|
|
8795
8938
|
cwd: serviceCwd,
|
|
8796
8939
|
runner: dockerConfig ? "docker" : "native",
|
|
8797
8940
|
shortcuts: (legacy.shortcuts || []).filter((s) => s.spawnCmd || s.label).map((s) => ({
|
|
8798
|
-
id: s.id ||
|
|
8941
|
+
id: s.id || randomUUID7(),
|
|
8799
8942
|
label: s.label || s.spawnCmd || "",
|
|
8800
8943
|
command: [s.spawnCmd, ...s.spawnArgs || []].filter(Boolean).join(" "),
|
|
8801
8944
|
...s.spawnOptions?.cwd ? { cwd: s.spawnOptions.cwd } : {}
|
|
@@ -8835,7 +8978,7 @@ async function runLegacyMigration(dataDir) {
|
|
|
8835
8978
|
);
|
|
8836
8979
|
if (!svcScopedEnv) {
|
|
8837
8980
|
svcScopedEnv = {
|
|
8838
|
-
id:
|
|
8981
|
+
id: randomUUID7(),
|
|
8839
8982
|
projectId: projectMonoId,
|
|
8840
8983
|
name: `${service?.name || name} (${globalEnv.name})`,
|
|
8841
8984
|
scope: "service",
|
|
@@ -8859,7 +9002,7 @@ async function runLegacyMigration(dataDir) {
|
|
|
8859
9002
|
const varPost = typeof varData === "object" ? String(varData.suffix ?? "") : "";
|
|
8860
9003
|
if (!varKey || existingKeys.has(cleanVarKey(varKey))) continue;
|
|
8861
9004
|
const cleaned = cleanVarKey(varKey);
|
|
8862
|
-
const varId =
|
|
9005
|
+
const varId = randomUUID7();
|
|
8863
9006
|
svcScopedEnv.variables[varId] = makeVariable(cleaned, varValue, varPre, varPost);
|
|
8864
9007
|
existingKeys.add(cleaned);
|
|
8865
9008
|
}
|
|
@@ -8879,7 +9022,7 @@ async function runLegacyMigration(dataDir) {
|
|
|
8879
9022
|
);
|
|
8880
9023
|
if (!svcScopedEnv) {
|
|
8881
9024
|
svcScopedEnv = {
|
|
8882
|
-
id:
|
|
9025
|
+
id: randomUUID7(),
|
|
8883
9026
|
projectId: projectMonoId,
|
|
8884
9027
|
name: `${service?.name || serviceName} (${globalEnv.name})`,
|
|
8885
9028
|
scope: "service",
|
|
@@ -8900,7 +9043,7 @@ async function runLegacyMigration(dataDir) {
|
|
|
8900
9043
|
const baseEntry = Object.entries(svcScopedEnv.variables).find(([, v]) => v.key === cleaned);
|
|
8901
9044
|
let varId = baseEntry?.[0];
|
|
8902
9045
|
if (!varId) {
|
|
8903
|
-
varId =
|
|
9046
|
+
varId = randomUUID7();
|
|
8904
9047
|
svcScopedEnv.variables[varId] = {
|
|
8905
9048
|
key: cleaned,
|
|
8906
9049
|
value: { value: "", pre: "", post: "", isSecret: false, shareWithAi: false, injectIntoAi: false, required: false, overrideOnly: false, description: "" }
|
|
@@ -8930,13 +9073,13 @@ async function runLegacyMigration(dataDir) {
|
|
|
8930
9073
|
flatOverrides[varId] = makeVariable(cleaned, value);
|
|
8931
9074
|
}
|
|
8932
9075
|
} else {
|
|
8933
|
-
flatOverrides[
|
|
9076
|
+
flatOverrides[randomUUID7()] = makeVariable(cleaned, value);
|
|
8934
9077
|
}
|
|
8935
9078
|
} else {
|
|
8936
9079
|
const cleaned = cleanVarKey(key);
|
|
8937
9080
|
const existingVarId = Object.entries(env2.variables).find(([, v]) => v.key === cleaned)?.[0];
|
|
8938
9081
|
if (!existingVarId) {
|
|
8939
|
-
const varId =
|
|
9082
|
+
const varId = randomUUID7();
|
|
8940
9083
|
env2.variables[varId] = makeVariable(cleaned, value);
|
|
8941
9084
|
varIdLookup.set(`${envId}:${cleaned}`, varId);
|
|
8942
9085
|
}
|
|
@@ -8965,7 +9108,7 @@ async function runLegacyMigration(dataDir) {
|
|
|
8965
9108
|
}
|
|
8966
9109
|
let existingSettings = {};
|
|
8967
9110
|
try {
|
|
8968
|
-
existingSettings = JSON.parse(await
|
|
9111
|
+
existingSettings = JSON.parse(await readFile8(join15(dataDir, "settings.json"), "utf-8"));
|
|
8969
9112
|
} catch {
|
|
8970
9113
|
}
|
|
8971
9114
|
const migratedParsers = legacyParsers.map((p) => ({
|
|
@@ -8986,11 +9129,11 @@ ${p.transform ?? ""}`,
|
|
|
8986
9129
|
...migratedParsers
|
|
8987
9130
|
]
|
|
8988
9131
|
};
|
|
8989
|
-
await atomicWrite(
|
|
8990
|
-
await atomicWrite(
|
|
8991
|
-
await atomicWrite(
|
|
8992
|
-
await atomicWrite(
|
|
8993
|
-
await atomicWrite(
|
|
9132
|
+
await atomicWrite(join15(dataDir, "projects.json"), runeProjects);
|
|
9133
|
+
await atomicWrite(join15(dataDir, "services.json"), runeServices);
|
|
9134
|
+
await atomicWrite(join15(dataDir, "environments.json"), runeEnvs);
|
|
9135
|
+
await atomicWrite(join15(dataDir, "environment-overrides.json"), flatOverrides);
|
|
9136
|
+
await atomicWrite(join15(dataDir, "settings.json"), newSettings);
|
|
8994
9137
|
const svcEnvCount = runeEnvs.filter((e) => e.scope === "service").length;
|
|
8995
9138
|
console.log(`[legacy-migration] Written: ${runeProjects.length} projects, ${runeServices.length} services, ${runeEnvs.length} environments (${svcEnvCount} service-scoped)`);
|
|
8996
9139
|
console.log(`[legacy-migration] Overrides: ${Object.keys(flatOverrides).length}, custom parsers: ${migratedParsers.length} (all disabled \u2014 rewrite required)`);
|
|
@@ -9004,9 +9147,9 @@ async function findLegacyKeyInBackup(dataDir) {
|
|
|
9004
9147
|
const entries2 = await readdir6(dataDir);
|
|
9005
9148
|
const backupDirs = entries2.filter((e) => e.startsWith("backup-")).sort((a, b) => a < b ? -1 : a > b ? 1 : 0).reverse();
|
|
9006
9149
|
for (const dir of backupDirs) {
|
|
9007
|
-
const keyJsonPath =
|
|
9150
|
+
const keyJsonPath = join15(dataDir, dir, "dbs", "encryption-key.json");
|
|
9008
9151
|
try {
|
|
9009
|
-
const raw = await
|
|
9152
|
+
const raw = await readFile8(keyJsonPath, "utf-8");
|
|
9010
9153
|
const parsed = JSON.parse(raw);
|
|
9011
9154
|
if (!parsed.encryptionKey) continue;
|
|
9012
9155
|
const sodium = await getSodium();
|
|
@@ -9027,8 +9170,8 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
9027
9170
|
const { resolve: resolve4 } = await import("path");
|
|
9028
9171
|
const abDataDir = resolve4(dataDir);
|
|
9029
9172
|
const candidateDirs = [
|
|
9030
|
-
|
|
9031
|
-
|
|
9173
|
+
join15(dirname6(env.DATA_DIR), ".runeya", "dbs", "overrides"),
|
|
9174
|
+
join15(abDataDir, "dbs", "overrides")
|
|
9032
9175
|
];
|
|
9033
9176
|
let overridesDir = null;
|
|
9034
9177
|
let overrideFiles = [];
|
|
@@ -9044,7 +9187,7 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
9044
9187
|
}
|
|
9045
9188
|
}
|
|
9046
9189
|
if (!overridesDir || overrideFiles.length === 0) return false;
|
|
9047
|
-
const legacyKeyPath =
|
|
9190
|
+
const legacyKeyPath = join15(overridesDir, "..", "encryption-key.json");
|
|
9048
9191
|
try {
|
|
9049
9192
|
await access2(legacyKeyPath);
|
|
9050
9193
|
return false;
|
|
@@ -9062,7 +9205,7 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
9062
9205
|
const envNameToId = {};
|
|
9063
9206
|
let envsRaw;
|
|
9064
9207
|
try {
|
|
9065
|
-
envsRaw = JSON.parse(await
|
|
9208
|
+
envsRaw = JSON.parse(await readFile8(join15(abDataDir, "environments.json"), "utf-8"));
|
|
9066
9209
|
for (const _env of envsRaw) {
|
|
9067
9210
|
const env2 = _env;
|
|
9068
9211
|
if (env2["name"] && env2["id"]) {
|
|
@@ -9081,7 +9224,7 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
9081
9224
|
let servicesRaw = [];
|
|
9082
9225
|
const serviceNameToId = {};
|
|
9083
9226
|
try {
|
|
9084
|
-
servicesRaw = JSON.parse(await
|
|
9227
|
+
servicesRaw = JSON.parse(await readFile8(join15(abDataDir, "services.json"), "utf-8"));
|
|
9085
9228
|
for (const _svc of servicesRaw) {
|
|
9086
9229
|
const svc = _svc;
|
|
9087
9230
|
if (svc["name"] && svc["id"]) serviceNameToId[svc["name"]] = svc["id"];
|
|
@@ -9098,7 +9241,7 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
9098
9241
|
const envName = baseName.slice(0, -"-environment".length);
|
|
9099
9242
|
let data;
|
|
9100
9243
|
try {
|
|
9101
|
-
data = await decryptLegacyFile(
|
|
9244
|
+
data = await decryptLegacyFile(join15(overridesDir, file), sodiumKey, sodium);
|
|
9102
9245
|
} catch (err) {
|
|
9103
9246
|
console.warn(`[override-migration] Failed to decrypt ${file}: ${err.message}`);
|
|
9104
9247
|
continue;
|
|
@@ -9120,12 +9263,12 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
9120
9263
|
if (isSameAsBase(value, baseVar)) continue;
|
|
9121
9264
|
flatOverrides[varId] = makeVariable(cleaned, value);
|
|
9122
9265
|
} else {
|
|
9123
|
-
flatOverrides[
|
|
9266
|
+
flatOverrides[randomUUID7()] = makeVariable(cleaned, value);
|
|
9124
9267
|
}
|
|
9125
9268
|
}
|
|
9126
9269
|
}
|
|
9127
9270
|
if (Object.keys(flatOverrides).length > 0) {
|
|
9128
|
-
await atomicWrite(
|
|
9271
|
+
await atomicWrite(join15(abDataDir, "environment-overrides.json"), flatOverrides);
|
|
9129
9272
|
console.log(`[override-migration] Written ${Object.keys(flatOverrides).length} override(s) to environment-overrides.json`);
|
|
9130
9273
|
}
|
|
9131
9274
|
let envsModified = false;
|
|
@@ -9135,7 +9278,7 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
9135
9278
|
const serviceName = baseName.slice(0, -"-envs".length);
|
|
9136
9279
|
let data;
|
|
9137
9280
|
try {
|
|
9138
|
-
data = await decryptLegacyFile(
|
|
9281
|
+
data = await decryptLegacyFile(join15(overridesDir, file), sodiumKey, sodium);
|
|
9139
9282
|
} catch (err) {
|
|
9140
9283
|
console.warn(`[override-migration] Failed to decrypt ${file}: ${err.message}`);
|
|
9141
9284
|
continue;
|
|
@@ -9157,7 +9300,7 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
9157
9300
|
);
|
|
9158
9301
|
if (!svcScopedEnv) {
|
|
9159
9302
|
svcScopedEnv = {
|
|
9160
|
-
id:
|
|
9303
|
+
id: randomUUID7(),
|
|
9161
9304
|
projectId: globalEnv["projectId"],
|
|
9162
9305
|
name: `${service?.["name"] || serviceName} (${globalEnv["name"]})`,
|
|
9163
9306
|
scope: "service",
|
|
@@ -9179,7 +9322,7 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
9179
9322
|
const baseEntry = Object.entries(svcScopedEnv["variables"]).find(([, v]) => v.key === cleaned);
|
|
9180
9323
|
let varId = baseEntry?.[0];
|
|
9181
9324
|
if (!varId) {
|
|
9182
|
-
varId =
|
|
9325
|
+
varId = randomUUID7();
|
|
9183
9326
|
svcScopedEnv["variables"][varId] = {
|
|
9184
9327
|
key: cleaned,
|
|
9185
9328
|
value: { value: "", pre: "", post: "", isSecret: false, shareWithAi: false, injectIntoAi: false, required: false, overrideOnly: false, description: "" }
|
|
@@ -9194,7 +9337,7 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
9194
9337
|
}
|
|
9195
9338
|
}
|
|
9196
9339
|
if (envsModified) {
|
|
9197
|
-
await atomicWrite(
|
|
9340
|
+
await atomicWrite(join15(abDataDir, "environments.json"), envsRaw);
|
|
9198
9341
|
console.log("[override-migration] Merged service overrides into environments.json");
|
|
9199
9342
|
}
|
|
9200
9343
|
const migratedDir = overridesDir.replace(/overrides$/, "overrides-migrated");
|
|
@@ -9209,7 +9352,7 @@ async function runOverrideOnlyMigration(dataDir) {
|
|
|
9209
9352
|
}
|
|
9210
9353
|
|
|
9211
9354
|
// ../server/src/services/server-state.ts
|
|
9212
|
-
import { join as
|
|
9355
|
+
import { join as join16 } from "path";
|
|
9213
9356
|
import { stat as stat10 } from "fs/promises";
|
|
9214
9357
|
var ENCRYPTED_KEY_FILENAME2 = ".encryption.key.enc";
|
|
9215
9358
|
var VERIFY_FILENAME2 = ".runeya-verify";
|
|
@@ -9219,22 +9362,22 @@ async function getServerState() {
|
|
|
9219
9362
|
let hasVerify = false;
|
|
9220
9363
|
let hasData = false;
|
|
9221
9364
|
try {
|
|
9222
|
-
await stat10(
|
|
9365
|
+
await stat10(join16(dataDir, ENCRYPTED_KEY_FILENAME2));
|
|
9223
9366
|
hasEncFile = true;
|
|
9224
9367
|
} catch {
|
|
9225
9368
|
}
|
|
9226
9369
|
try {
|
|
9227
|
-
await stat10(
|
|
9370
|
+
await stat10(join16(dataDir, VERIFY_FILENAME2));
|
|
9228
9371
|
hasVerify = true;
|
|
9229
9372
|
} catch {
|
|
9230
9373
|
}
|
|
9231
9374
|
try {
|
|
9232
|
-
await stat10(
|
|
9375
|
+
await stat10(join16(dataDir, "projects.json"));
|
|
9233
9376
|
hasData = true;
|
|
9234
9377
|
} catch {
|
|
9235
9378
|
}
|
|
9236
9379
|
try {
|
|
9237
|
-
await stat10(
|
|
9380
|
+
await stat10(join16(dataDir, "project.json"));
|
|
9238
9381
|
hasData = true;
|
|
9239
9382
|
} catch {
|
|
9240
9383
|
}
|
|
@@ -10369,7 +10512,7 @@ async function createLocalServer() {
|
|
|
10369
10512
|
stopClaudeTranscriptWatcher();
|
|
10370
10513
|
stopCodexTranscriptWatcher();
|
|
10371
10514
|
imageCleanupService.stop();
|
|
10372
|
-
cloudSyncBridge.stopAll();
|
|
10515
|
+
void cloudSyncBridge.stopAll();
|
|
10373
10516
|
await Promise.all([
|
|
10374
10517
|
unregisterInstance(),
|
|
10375
10518
|
agentSpawner.shutdown(),
|
|
@@ -10386,7 +10529,7 @@ async function createLocalServer() {
|
|
|
10386
10529
|
]);
|
|
10387
10530
|
console.log("[server] Shutdown complete");
|
|
10388
10531
|
};
|
|
10389
|
-
const { initCompanion } = await import("./companion-
|
|
10532
|
+
const { initCompanion } = await import("./companion-HEJHC3UR.js");
|
|
10390
10533
|
initCompanion();
|
|
10391
10534
|
return { app, server, wss, shutdown };
|
|
10392
10535
|
}
|
|
@@ -10517,7 +10660,7 @@ function onTrayServicesChanged(listener) {
|
|
|
10517
10660
|
|
|
10518
10661
|
// ../server/src/services/tray-icon.ts
|
|
10519
10662
|
import { mkdir as mkdir12, writeFile as writeFile10, rename as rename8 } from "fs/promises";
|
|
10520
|
-
import { join as
|
|
10663
|
+
import { join as join17 } from "path";
|
|
10521
10664
|
|
|
10522
10665
|
// ../server/src/services/png-to-ico.ts
|
|
10523
10666
|
function isPng(bytes) {
|
|
@@ -10677,7 +10820,7 @@ var FETCH_TIMEOUT_MS = 3e3;
|
|
|
10677
10820
|
var CACHE_TTL_MS = 10 * 6e4;
|
|
10678
10821
|
var cache2 = /* @__PURE__ */ new Map();
|
|
10679
10822
|
function trayIconDir() {
|
|
10680
|
-
return
|
|
10823
|
+
return join17(machineRoot(), "tray-icons");
|
|
10681
10824
|
}
|
|
10682
10825
|
async function resolveTrayIcon(platform = process.platform) {
|
|
10683
10826
|
const orgId = getCurrentProject()?.orgId;
|
|
@@ -10706,7 +10849,7 @@ async function renderThemedIcon(platform) {
|
|
|
10706
10849
|
async function writeTrayIcon(stem, png, platform) {
|
|
10707
10850
|
const dir = trayIconDir();
|
|
10708
10851
|
await mkdir12(dir, { recursive: true });
|
|
10709
|
-
const path =
|
|
10852
|
+
const path = join17(dir, stem);
|
|
10710
10853
|
if (platform === "win32") {
|
|
10711
10854
|
const ico = pngToIco(png);
|
|
10712
10855
|
return ico ? writeAtomic(`${path}.ico`, ico) : null;
|
|
@@ -10833,4 +10976,4 @@ export {
|
|
|
10833
10976
|
startProcess,
|
|
10834
10977
|
stopProcess
|
|
10835
10978
|
};
|
|
10836
|
-
//# sourceMappingURL=src-
|
|
10979
|
+
//# sourceMappingURL=src-YUVA6WCM.js.map
|