mindwire 0.1.30 → 0.1.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-RN7ERVJ2.js → chunk-H2I3VRBS.js} +183 -8
- package/dist/chunk-H2I3VRBS.js.map +1 -0
- package/dist/cli.js +47 -10
- package/dist/cli.js.map +1 -1
- package/dist/computer/connection-progress.d.ts +14 -0
- package/dist/computer/lifecycle.d.ts +1 -0
- package/dist/computer/relay-health.d.ts +10 -0
- package/dist/computer/relay-output.d.ts +19 -0
- package/dist/computer/relay.d.ts +4 -1
- package/dist/{controller-DIJKMWWU.js → controller-QBC6L7AT.js} +199 -120
- package/dist/controller-QBC6L7AT.js.map +1 -0
- package/dist/{controller-handoff-4GXF4ATR.js → controller-handoff-NFDOLPJL.js} +3 -3
- package/dist/{controller-handoff-4GXF4ATR.js.map → controller-handoff-NFDOLPJL.js.map} +1 -1
- package/dist/index.cjs +177 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +175 -4
- package/dist/index.js.map +1 -1
- package/dist/project-sync.d.ts +101 -0
- package/dist/types.d.ts +4 -0
- package/dist/workspace.d.ts +27 -4
- package/package.json +1 -1
- package/dist/chunk-RN7ERVJ2.js.map +0 -1
- package/dist/controller-DIJKMWWU.js.map +0 -1
|
@@ -79,7 +79,7 @@ function computerPairingURI(invitation) {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
// src/version.ts
|
|
82
|
-
var SDK_VERSION = "0.1.
|
|
82
|
+
var SDK_VERSION = "0.1.33" ;
|
|
83
83
|
function versionAtLeast(actual, desired) {
|
|
84
84
|
if (actual === desired) return true;
|
|
85
85
|
if (!actual || !/^\d+\.\d+\.\d+$/.test(actual) || !/^\d+\.\d+\.\d+$/.test(desired)) return false;
|
|
@@ -665,6 +665,171 @@ var Run = class _Run {
|
|
|
665
665
|
}
|
|
666
666
|
};
|
|
667
667
|
|
|
668
|
+
// src/project-sync.ts
|
|
669
|
+
var ProjectSyncError = class extends MindwireError {
|
|
670
|
+
constructor(operation) {
|
|
671
|
+
super(operation.error ?? (operation.status === "conflicts" ? "Changes conflict. Both workspace copies and their checkpoints are preserved." : `Project synchronization ${operation.status}.`));
|
|
672
|
+
this.operation = operation;
|
|
673
|
+
this.name = "ProjectSyncError";
|
|
674
|
+
}
|
|
675
|
+
operation;
|
|
676
|
+
};
|
|
677
|
+
var active = (o) => ["queued", "exporting", "preparing", "applying"].includes(o.status);
|
|
678
|
+
var prefix = "/workspace/sync";
|
|
679
|
+
function delay2(ms, signal) {
|
|
680
|
+
signal?.throwIfAborted();
|
|
681
|
+
return new Promise((resolve, reject) => {
|
|
682
|
+
const done = () => {
|
|
683
|
+
signal?.removeEventListener("abort", abort);
|
|
684
|
+
resolve();
|
|
685
|
+
};
|
|
686
|
+
const timer = setTimeout(done, ms);
|
|
687
|
+
const abort = () => {
|
|
688
|
+
clearTimeout(timer);
|
|
689
|
+
signal?.removeEventListener("abort", abort);
|
|
690
|
+
reject(signal?.reason);
|
|
691
|
+
};
|
|
692
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
var ProjectSyncApi = class {
|
|
696
|
+
constructor(mw) {
|
|
697
|
+
this.mw = mw;
|
|
698
|
+
}
|
|
699
|
+
mw;
|
|
700
|
+
flights = /* @__PURE__ */ new Map();
|
|
701
|
+
export(request, options = {}) {
|
|
702
|
+
return this.mw.http.request("POST", `${prefix}/exports`, { body: request, ...options });
|
|
703
|
+
}
|
|
704
|
+
import(request, options = {}) {
|
|
705
|
+
return this.mw.http.request("POST", `${prefix}/imports`, { body: request, ...options });
|
|
706
|
+
}
|
|
707
|
+
async list(options = {}) {
|
|
708
|
+
const response = await this.mw.http.request("GET", `${prefix}/operations`, options);
|
|
709
|
+
return response.operations;
|
|
710
|
+
}
|
|
711
|
+
get(id, options = {}) {
|
|
712
|
+
return this.mw.http.request("GET", `${prefix}/operations/${encodeURIComponent(id)}`, options);
|
|
713
|
+
}
|
|
714
|
+
retry(id, options = {}) {
|
|
715
|
+
return this.mw.http.request("POST", `${prefix}/operations/${encodeURIComponent(id)}/retry`, options);
|
|
716
|
+
}
|
|
717
|
+
cancel(id) {
|
|
718
|
+
return this.mw.http.request("POST", `${prefix}/operations/${encodeURIComponent(id)}/cancel`);
|
|
719
|
+
}
|
|
720
|
+
checkpoint(id, options = {}) {
|
|
721
|
+
return this.mw.http.request("GET", `${prefix}/checkpoints/${encodeURIComponent(id)}`, options);
|
|
722
|
+
}
|
|
723
|
+
acceptCheckpoint(checkpoint, options = {}) {
|
|
724
|
+
return this.mw.http.request("PUT", `${prefix}/checkpoints/${encodeURIComponent(checkpoint.id)}`, { body: checkpoint, ...options });
|
|
725
|
+
}
|
|
726
|
+
objects(id, cursor = 0, options = {}) {
|
|
727
|
+
return this.mw.http.request("GET", `${prefix}/checkpoints/${encodeURIComponent(id)}/objects`, { query: { cursor }, ...options });
|
|
728
|
+
}
|
|
729
|
+
async missing(objects, options = {}) {
|
|
730
|
+
const response = await this.mw.http.request("POST", `${prefix}/objects/missing`, { body: { objects }, ...options });
|
|
731
|
+
return response.objects;
|
|
732
|
+
}
|
|
733
|
+
/** Base64 chunk, at most 256 KiB before encoding. */
|
|
734
|
+
async getObject(id, options = {}) {
|
|
735
|
+
const response = await this.mw.http.request("GET", `${prefix}/objects/${encodeURIComponent(id)}`, options);
|
|
736
|
+
return response.data;
|
|
737
|
+
}
|
|
738
|
+
async putObject(id, data, options = {}) {
|
|
739
|
+
await this.mw.http.request("PUT", `${prefix}/objects/${encodeURIComponent(id)}`, { body: { data }, ...options });
|
|
740
|
+
}
|
|
741
|
+
async wait(id, options = {}) {
|
|
742
|
+
for (; ; ) {
|
|
743
|
+
const o = await this.get(id, { signal: options.signal });
|
|
744
|
+
options.onUpdate?.(o);
|
|
745
|
+
if (!active(o)) return o;
|
|
746
|
+
await delay2(500, options.signal);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
/** Repeating this relay skips acknowledged checkpoints and verified chunks.
|
|
750
|
+
* Aborting detaches the relay; daemon export/apply operations remain durable.
|
|
751
|
+
*/
|
|
752
|
+
async relayCheckpoint(target, id, options = {}) {
|
|
753
|
+
const visited = /* @__PURE__ */ new Set();
|
|
754
|
+
const visit = async (checkpointId) => {
|
|
755
|
+
options.signal?.throwIfAborted();
|
|
756
|
+
if (visited.has(checkpointId)) return;
|
|
757
|
+
visited.add(checkpointId);
|
|
758
|
+
try {
|
|
759
|
+
await target.checkpoint(checkpointId, options);
|
|
760
|
+
return;
|
|
761
|
+
} catch (error) {
|
|
762
|
+
if (!(error instanceof ApiError) || error.status !== 404) throw error;
|
|
763
|
+
}
|
|
764
|
+
const checkpoint = await this.checkpoint(checkpointId, options);
|
|
765
|
+
for (const parent of checkpoint.parents) await visit(parent);
|
|
766
|
+
let cursor = 0;
|
|
767
|
+
do {
|
|
768
|
+
const page = await this.objects(checkpointId, cursor, options);
|
|
769
|
+
const missing = await target.missing(page.objects, options);
|
|
770
|
+
for (const object of missing) {
|
|
771
|
+
const data = await this.getObject(object, options);
|
|
772
|
+
await target.putObject(object, data, options);
|
|
773
|
+
const padding = data.endsWith("==") ? 2 : data.endsWith("=") ? 1 : 0;
|
|
774
|
+
options.onBytes?.(Math.floor(data.length * 3 / 4) - padding);
|
|
775
|
+
}
|
|
776
|
+
cursor = page.next ?? 0;
|
|
777
|
+
} while (cursor);
|
|
778
|
+
await target.acceptCheckpoint(checkpoint, options);
|
|
779
|
+
};
|
|
780
|
+
await visit(id);
|
|
781
|
+
}
|
|
782
|
+
/** Safe X → Y and Y → X. Persist request.id until acknowledged. A conflict
|
|
783
|
+
* throws ProjectSyncError carrying the complete conflict/recovery operation.
|
|
784
|
+
*/
|
|
785
|
+
switchTo(target, request, options = {}) {
|
|
786
|
+
const intent = JSON.stringify(request);
|
|
787
|
+
const old = this.flights.get(request.id);
|
|
788
|
+
if (old) {
|
|
789
|
+
if (old.intent !== intent || old.target !== target) return Promise.reject(new MindwireError("This sync ID already belongs to a different request or destination."));
|
|
790
|
+
return old.result;
|
|
791
|
+
}
|
|
792
|
+
const work = async () => {
|
|
793
|
+
if (target === this || target.mw.http === this.mw.http) throw new MindwireError("Choose another workspace for this project.");
|
|
794
|
+
let accepted;
|
|
795
|
+
try {
|
|
796
|
+
accepted = await target.get(`${request.id}-import`, options);
|
|
797
|
+
} catch (error) {
|
|
798
|
+
if (!(error instanceof ApiError) || error.status !== 404) throw error;
|
|
799
|
+
}
|
|
800
|
+
if (accepted) {
|
|
801
|
+
if ((accepted.path ?? "") !== (request.path ?? "")) throw new MindwireError("This sync ID belongs to a different destination folder.");
|
|
802
|
+
const operation = await target.wait(accepted.id, {
|
|
803
|
+
signal: options.signal,
|
|
804
|
+
onUpdate: (operation2) => options.onProgress?.({ phase: "apply", transferredBytes: 0, operation: operation2 })
|
|
805
|
+
});
|
|
806
|
+
if (operation.status !== "succeeded") throw new ProjectSyncError(operation);
|
|
807
|
+
return operation;
|
|
808
|
+
}
|
|
809
|
+
const health = await Promise.all([this.mw.health(), target.mw.health()]);
|
|
810
|
+
if (health.some((h) => (h.projectSyncVersion ?? 0) < 1)) throw new MindwireError("Update Mindwire on both workspaces to switch this project.");
|
|
811
|
+
let bytes = 0;
|
|
812
|
+
const emit2 = (phase, operation) => options.onProgress?.({ phase, transferredBytes: bytes, operation });
|
|
813
|
+
emit2("checkpoint");
|
|
814
|
+
let o = await this.export({ id: `${request.id}-export`, projectId: request.projectId }, options);
|
|
815
|
+
o = await this.wait(o.id, { signal: options.signal, onUpdate: (value) => emit2("checkpoint", value) });
|
|
816
|
+
if (o.status !== "succeeded" || !o.resultCheckpointId) throw new ProjectSyncError(o);
|
|
817
|
+
emit2("transfer");
|
|
818
|
+
await this.relayCheckpoint(target, o.resultCheckpointId, { signal: options.signal, onBytes: (n) => {
|
|
819
|
+
bytes += n;
|
|
820
|
+
emit2("transfer");
|
|
821
|
+
} });
|
|
822
|
+
o = await target.import({ id: `${request.id}-import`, checkpointId: o.resultCheckpointId, path: request.path }, options);
|
|
823
|
+
o = await target.wait(o.id, { signal: options.signal, onUpdate: (value) => emit2("apply", value) });
|
|
824
|
+
if (o.status !== "succeeded") throw new ProjectSyncError(o);
|
|
825
|
+
return o;
|
|
826
|
+
};
|
|
827
|
+
const result = work().finally(() => this.flights.delete(request.id));
|
|
828
|
+
this.flights.set(request.id, { intent, target, result });
|
|
829
|
+
return result;
|
|
830
|
+
}
|
|
831
|
+
};
|
|
832
|
+
|
|
668
833
|
// src/workspace.ts
|
|
669
834
|
var ProjectOperationsApi = class {
|
|
670
835
|
constructor(mw) {
|
|
@@ -736,6 +901,7 @@ var WorkspaceCollection = class {
|
|
|
736
901
|
var WorkspaceApi = class {
|
|
737
902
|
constructor(mw) {
|
|
738
903
|
this.mw = mw;
|
|
904
|
+
this.sync = new ProjectSyncApi(mw);
|
|
739
905
|
this.git = new GitAccessApi(mw);
|
|
740
906
|
this.operations = new ProjectOperationsApi(mw);
|
|
741
907
|
this.agents = new WorkspaceCollection(mw, "agents");
|
|
@@ -743,6 +909,7 @@ var WorkspaceApi = class {
|
|
|
743
909
|
this.chats = new WorkspaceCollection(mw, "chats");
|
|
744
910
|
}
|
|
745
911
|
mw;
|
|
912
|
+
sync;
|
|
746
913
|
git;
|
|
747
914
|
operations;
|
|
748
915
|
agents;
|
|
@@ -751,6 +918,10 @@ var WorkspaceApi = class {
|
|
|
751
918
|
snapshot(options = {}) {
|
|
752
919
|
return this.mw.http.request("GET", "/workspace", { query: options });
|
|
753
920
|
}
|
|
921
|
+
/** Read the saved icon, or preview a candidate relative path within the project. Requires projectIconsVersion >= 1. */
|
|
922
|
+
projectIcon(projectId, path2) {
|
|
923
|
+
return this.mw.http.request("GET", `/workspace/projects/${encodeURIComponent(projectId)}/icon`, { query: { path: path2 } });
|
|
924
|
+
}
|
|
754
925
|
/** Start an operation owned by the daemon. The same ID/payload returns the existing operation. */
|
|
755
926
|
createProject(request) {
|
|
756
927
|
return this.mw.http.request("POST", "/workspace/projects", { body: request });
|
|
@@ -807,7 +978,7 @@ var GitAccessApi = class {
|
|
|
807
978
|
run(projectId, operation, auth) {
|
|
808
979
|
return this.mw.http.request("POST", `/workspace/projects/${encodeURIComponent(projectId)}/git/${operation}`, { body: { auth } });
|
|
809
980
|
}
|
|
810
|
-
/** Requires health.gitOperationsVersion >= 1 (>= 2 for
|
|
981
|
+
/** Requires health.gitOperationsVersion >= 1 (>= 2 for switch/create, >= 4 for restore_commit, >= 5 for rename/delete). Acceptance persists before Git runs;
|
|
811
982
|
* disconnecting only detaches the client. The same ID/intent never runs twice.
|
|
812
983
|
*/
|
|
813
984
|
start(projectId, request) {
|
|
@@ -817,7 +988,7 @@ var GitAccessApi = class {
|
|
|
817
988
|
const result = await this.mw.http.request(
|
|
818
989
|
"GET",
|
|
819
990
|
`/workspace/projects/${encodeURIComponent(projectId)}/git/operations`,
|
|
820
|
-
{ query: { active: activeOnly, actionsVersion:
|
|
991
|
+
{ query: { active: activeOnly, actionsVersion: 5 } }
|
|
821
992
|
);
|
|
822
993
|
return result.operations;
|
|
823
994
|
}
|
|
@@ -1955,9 +2126,11 @@ async function ensureComputer(directory, cliPath, patch = {}, onProgress, option
|
|
|
1955
2126
|
let launchFailure;
|
|
1956
2127
|
const waitUntilReady = async () => {
|
|
1957
2128
|
let phase;
|
|
2129
|
+
let lastState;
|
|
1958
2130
|
for (let attempt = 0; attempt < 1200; attempt++) {
|
|
1959
2131
|
options.signal?.throwIfAborted();
|
|
1960
2132
|
const controller = await readJSON(path.join(directory, "computer-controller.json"));
|
|
2133
|
+
lastState = controller;
|
|
1961
2134
|
if (launchFailure) throw launchFailure;
|
|
1962
2135
|
if (launchedPID && controller?.pid !== launchedPID) {
|
|
1963
2136
|
await setTimeout$1(250);
|
|
@@ -1971,7 +2144,9 @@ async function ensureComputer(directory, cliPath, patch = {}, onProgress, option
|
|
|
1971
2144
|
}
|
|
1972
2145
|
await setTimeout$1(250);
|
|
1973
2146
|
}
|
|
1974
|
-
|
|
2147
|
+
const lastStep = lastState?.errorCode === "dns" ? "Your DNS resolver still cannot find the tunnel address." : lastState?.error ?? phase ?? "The background service hasn't reported readiness.";
|
|
2148
|
+
const recovering = lastState?.recovering && await processStateAlive(lastState).catch(() => false);
|
|
2149
|
+
throw new Error(`Mindwire's connection is not ready. ${lastStep}${recovering ? " Background recovery continues." : ""} Run mindwire status for the current state, then mindwire connect to retry.`);
|
|
1975
2150
|
};
|
|
1976
2151
|
if (current) {
|
|
1977
2152
|
if (Object.keys(patch).some((key) => JSON.stringify(config[key]) !== JSON.stringify(previous?.[key]))) {
|
|
@@ -2014,7 +2189,7 @@ async function ensureComputer(directory, cliPath, patch = {}, onProgress, option
|
|
|
2014
2189
|
let controller = await readJSON(path.join(directory, "computer-controller.json"));
|
|
2015
2190
|
if (existing && controller && !compatible(controller) && await processStateAlive(controller)) {
|
|
2016
2191
|
onProgress?.("Refreshing the background connection service\u2026");
|
|
2017
|
-
const { handoffController } = await import('./controller-handoff-
|
|
2192
|
+
const { handoffController } = await import('./controller-handoff-NFDOLPJL.js');
|
|
2018
2193
|
await handoffController(directory, controller, config, await existing.computer.info());
|
|
2019
2194
|
controller = void 0;
|
|
2020
2195
|
}
|
|
@@ -2048,7 +2223,7 @@ async function ensureComputer(directory, cliPath, patch = {}, onProgress, option
|
|
|
2048
2223
|
}
|
|
2049
2224
|
}
|
|
2050
2225
|
async function superviseComputer(directory) {
|
|
2051
|
-
const controller = await import('./controller-
|
|
2226
|
+
const controller = await import('./controller-QBC6L7AT.js');
|
|
2052
2227
|
await controller.superviseComputer(directory);
|
|
2053
2228
|
}
|
|
2054
2229
|
async function stopComputer(directory, force = false) {
|
|
@@ -2073,5 +2248,5 @@ async function stopComputer(directory, force = false) {
|
|
|
2073
2248
|
}
|
|
2074
2249
|
|
|
2075
2250
|
export { CONTROLLER_PROTOCOL, SDK_VERSION, acquireProcessLock, adoptProcess, computerClient, computerPairingQRData, computerPairingURI, currentProcessIdentity, defaultStateDirectory, directRoutes, ensureComputer, ensureDaemonBinary, ownChild, processIdentity, processStateAlive, readJSON, stopComputer, superviseComputer, writeJSON };
|
|
2076
|
-
//# sourceMappingURL=chunk-
|
|
2077
|
-
//# sourceMappingURL=chunk-
|
|
2251
|
+
//# sourceMappingURL=chunk-H2I3VRBS.js.map
|
|
2252
|
+
//# sourceMappingURL=chunk-H2I3VRBS.js.map
|