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
package/dist/index.d.ts
CHANGED
|
@@ -35,8 +35,10 @@ export * from "./types.js";
|
|
|
35
35
|
export { ServiceApi } from "./service.js";
|
|
36
36
|
export type { ServiceUpdateState, ServiceUpdateLease } from "./service.js";
|
|
37
37
|
export { WorkspaceApi, WorkspaceCollection, ProjectOperationsApi, GitAccessApi } from "./workspace.js";
|
|
38
|
+
export { ProjectSyncApi, ProjectSyncError } from "./project-sync.js";
|
|
39
|
+
export type { ProjectSyncEntry, ProjectSyncCheckpoint, ProjectSyncRequest, ProjectSyncOperation, ProjectSyncConflict, ProjectSyncProgress } from "./project-sync.js";
|
|
38
40
|
export type { ProjectRequest, ProjectAuth, ProjectOperation, ProjectRemoveRequest, GitConnection, GitAccessState, ProjectGitState, GitAction, GitIdentity, GitIdentityScope, GitIdentitySettings, GitIdentityUpdate, GitOperationRequest, GitOperation } from "./workspace.js";
|
|
39
|
-
export type { WorkspaceRecord, WorkspaceAgent, WorkspaceProject, WorkspaceChat, WorkspaceKind, WorkspaceInput, WorkspaceImport, WorkspaceSnapshot } from "./workspace.js";
|
|
41
|
+
export type { WorkspaceRecord, WorkspaceAgent, WorkspaceProject, WorkspaceChat, WorkspaceKind, WorkspaceInput, WorkspaceImport, WorkspaceSnapshot, ProjectIcon } from "./workspace.js";
|
|
40
42
|
export * from "./surfaces.js";
|
|
41
43
|
export * from "./execution.js";
|
|
42
44
|
export * from "./computer.js";
|
package/dist/index.js
CHANGED
|
@@ -425,6 +425,171 @@ var Run = class _Run {
|
|
|
425
425
|
}
|
|
426
426
|
};
|
|
427
427
|
|
|
428
|
+
// src/project-sync.ts
|
|
429
|
+
var ProjectSyncError = class extends MindwireError {
|
|
430
|
+
constructor(operation) {
|
|
431
|
+
super(operation.error ?? (operation.status === "conflicts" ? "Changes conflict. Both workspace copies and their checkpoints are preserved." : `Project synchronization ${operation.status}.`));
|
|
432
|
+
this.operation = operation;
|
|
433
|
+
this.name = "ProjectSyncError";
|
|
434
|
+
}
|
|
435
|
+
operation;
|
|
436
|
+
};
|
|
437
|
+
var active = (o) => ["queued", "exporting", "preparing", "applying"].includes(o.status);
|
|
438
|
+
var prefix = "/workspace/sync";
|
|
439
|
+
function delay(ms, signal) {
|
|
440
|
+
signal?.throwIfAborted();
|
|
441
|
+
return new Promise((resolve, reject) => {
|
|
442
|
+
const done = () => {
|
|
443
|
+
signal?.removeEventListener("abort", abort);
|
|
444
|
+
resolve();
|
|
445
|
+
};
|
|
446
|
+
const timer = setTimeout(done, ms);
|
|
447
|
+
const abort = () => {
|
|
448
|
+
clearTimeout(timer);
|
|
449
|
+
signal?.removeEventListener("abort", abort);
|
|
450
|
+
reject(signal?.reason);
|
|
451
|
+
};
|
|
452
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
var ProjectSyncApi = class {
|
|
456
|
+
constructor(mw) {
|
|
457
|
+
this.mw = mw;
|
|
458
|
+
}
|
|
459
|
+
mw;
|
|
460
|
+
flights = /* @__PURE__ */ new Map();
|
|
461
|
+
export(request, options = {}) {
|
|
462
|
+
return this.mw.http.request("POST", `${prefix}/exports`, { body: request, ...options });
|
|
463
|
+
}
|
|
464
|
+
import(request, options = {}) {
|
|
465
|
+
return this.mw.http.request("POST", `${prefix}/imports`, { body: request, ...options });
|
|
466
|
+
}
|
|
467
|
+
async list(options = {}) {
|
|
468
|
+
const response = await this.mw.http.request("GET", `${prefix}/operations`, options);
|
|
469
|
+
return response.operations;
|
|
470
|
+
}
|
|
471
|
+
get(id, options = {}) {
|
|
472
|
+
return this.mw.http.request("GET", `${prefix}/operations/${encodeURIComponent(id)}`, options);
|
|
473
|
+
}
|
|
474
|
+
retry(id, options = {}) {
|
|
475
|
+
return this.mw.http.request("POST", `${prefix}/operations/${encodeURIComponent(id)}/retry`, options);
|
|
476
|
+
}
|
|
477
|
+
cancel(id) {
|
|
478
|
+
return this.mw.http.request("POST", `${prefix}/operations/${encodeURIComponent(id)}/cancel`);
|
|
479
|
+
}
|
|
480
|
+
checkpoint(id, options = {}) {
|
|
481
|
+
return this.mw.http.request("GET", `${prefix}/checkpoints/${encodeURIComponent(id)}`, options);
|
|
482
|
+
}
|
|
483
|
+
acceptCheckpoint(checkpoint, options = {}) {
|
|
484
|
+
return this.mw.http.request("PUT", `${prefix}/checkpoints/${encodeURIComponent(checkpoint.id)}`, { body: checkpoint, ...options });
|
|
485
|
+
}
|
|
486
|
+
objects(id, cursor = 0, options = {}) {
|
|
487
|
+
return this.mw.http.request("GET", `${prefix}/checkpoints/${encodeURIComponent(id)}/objects`, { query: { cursor }, ...options });
|
|
488
|
+
}
|
|
489
|
+
async missing(objects, options = {}) {
|
|
490
|
+
const response = await this.mw.http.request("POST", `${prefix}/objects/missing`, { body: { objects }, ...options });
|
|
491
|
+
return response.objects;
|
|
492
|
+
}
|
|
493
|
+
/** Base64 chunk, at most 256 KiB before encoding. */
|
|
494
|
+
async getObject(id, options = {}) {
|
|
495
|
+
const response = await this.mw.http.request("GET", `${prefix}/objects/${encodeURIComponent(id)}`, options);
|
|
496
|
+
return response.data;
|
|
497
|
+
}
|
|
498
|
+
async putObject(id, data, options = {}) {
|
|
499
|
+
await this.mw.http.request("PUT", `${prefix}/objects/${encodeURIComponent(id)}`, { body: { data }, ...options });
|
|
500
|
+
}
|
|
501
|
+
async wait(id, options = {}) {
|
|
502
|
+
for (; ; ) {
|
|
503
|
+
const o = await this.get(id, { signal: options.signal });
|
|
504
|
+
options.onUpdate?.(o);
|
|
505
|
+
if (!active(o)) return o;
|
|
506
|
+
await delay(500, options.signal);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
/** Repeating this relay skips acknowledged checkpoints and verified chunks.
|
|
510
|
+
* Aborting detaches the relay; daemon export/apply operations remain durable.
|
|
511
|
+
*/
|
|
512
|
+
async relayCheckpoint(target, id, options = {}) {
|
|
513
|
+
const visited = /* @__PURE__ */ new Set();
|
|
514
|
+
const visit = async (checkpointId) => {
|
|
515
|
+
options.signal?.throwIfAborted();
|
|
516
|
+
if (visited.has(checkpointId)) return;
|
|
517
|
+
visited.add(checkpointId);
|
|
518
|
+
try {
|
|
519
|
+
await target.checkpoint(checkpointId, options);
|
|
520
|
+
return;
|
|
521
|
+
} catch (error) {
|
|
522
|
+
if (!(error instanceof ApiError) || error.status !== 404) throw error;
|
|
523
|
+
}
|
|
524
|
+
const checkpoint = await this.checkpoint(checkpointId, options);
|
|
525
|
+
for (const parent of checkpoint.parents) await visit(parent);
|
|
526
|
+
let cursor = 0;
|
|
527
|
+
do {
|
|
528
|
+
const page = await this.objects(checkpointId, cursor, options);
|
|
529
|
+
const missing = await target.missing(page.objects, options);
|
|
530
|
+
for (const object of missing) {
|
|
531
|
+
const data = await this.getObject(object, options);
|
|
532
|
+
await target.putObject(object, data, options);
|
|
533
|
+
const padding = data.endsWith("==") ? 2 : data.endsWith("=") ? 1 : 0;
|
|
534
|
+
options.onBytes?.(Math.floor(data.length * 3 / 4) - padding);
|
|
535
|
+
}
|
|
536
|
+
cursor = page.next ?? 0;
|
|
537
|
+
} while (cursor);
|
|
538
|
+
await target.acceptCheckpoint(checkpoint, options);
|
|
539
|
+
};
|
|
540
|
+
await visit(id);
|
|
541
|
+
}
|
|
542
|
+
/** Safe X → Y and Y → X. Persist request.id until acknowledged. A conflict
|
|
543
|
+
* throws ProjectSyncError carrying the complete conflict/recovery operation.
|
|
544
|
+
*/
|
|
545
|
+
switchTo(target, request, options = {}) {
|
|
546
|
+
const intent = JSON.stringify(request);
|
|
547
|
+
const old = this.flights.get(request.id);
|
|
548
|
+
if (old) {
|
|
549
|
+
if (old.intent !== intent || old.target !== target) return Promise.reject(new MindwireError("This sync ID already belongs to a different request or destination."));
|
|
550
|
+
return old.result;
|
|
551
|
+
}
|
|
552
|
+
const work = async () => {
|
|
553
|
+
if (target === this || target.mw.http === this.mw.http) throw new MindwireError("Choose another workspace for this project.");
|
|
554
|
+
let accepted;
|
|
555
|
+
try {
|
|
556
|
+
accepted = await target.get(`${request.id}-import`, options);
|
|
557
|
+
} catch (error) {
|
|
558
|
+
if (!(error instanceof ApiError) || error.status !== 404) throw error;
|
|
559
|
+
}
|
|
560
|
+
if (accepted) {
|
|
561
|
+
if ((accepted.path ?? "") !== (request.path ?? "")) throw new MindwireError("This sync ID belongs to a different destination folder.");
|
|
562
|
+
const operation = await target.wait(accepted.id, {
|
|
563
|
+
signal: options.signal,
|
|
564
|
+
onUpdate: (operation2) => options.onProgress?.({ phase: "apply", transferredBytes: 0, operation: operation2 })
|
|
565
|
+
});
|
|
566
|
+
if (operation.status !== "succeeded") throw new ProjectSyncError(operation);
|
|
567
|
+
return operation;
|
|
568
|
+
}
|
|
569
|
+
const health = await Promise.all([this.mw.health(), target.mw.health()]);
|
|
570
|
+
if (health.some((h) => (h.projectSyncVersion ?? 0) < 1)) throw new MindwireError("Update Mindwire on both workspaces to switch this project.");
|
|
571
|
+
let bytes = 0;
|
|
572
|
+
const emit2 = (phase, operation) => options.onProgress?.({ phase, transferredBytes: bytes, operation });
|
|
573
|
+
emit2("checkpoint");
|
|
574
|
+
let o = await this.export({ id: `${request.id}-export`, projectId: request.projectId }, options);
|
|
575
|
+
o = await this.wait(o.id, { signal: options.signal, onUpdate: (value) => emit2("checkpoint", value) });
|
|
576
|
+
if (o.status !== "succeeded" || !o.resultCheckpointId) throw new ProjectSyncError(o);
|
|
577
|
+
emit2("transfer");
|
|
578
|
+
await this.relayCheckpoint(target, o.resultCheckpointId, { signal: options.signal, onBytes: (n) => {
|
|
579
|
+
bytes += n;
|
|
580
|
+
emit2("transfer");
|
|
581
|
+
} });
|
|
582
|
+
o = await target.import({ id: `${request.id}-import`, checkpointId: o.resultCheckpointId, path: request.path }, options);
|
|
583
|
+
o = await target.wait(o.id, { signal: options.signal, onUpdate: (value) => emit2("apply", value) });
|
|
584
|
+
if (o.status !== "succeeded") throw new ProjectSyncError(o);
|
|
585
|
+
return o;
|
|
586
|
+
};
|
|
587
|
+
const result = work().finally(() => this.flights.delete(request.id));
|
|
588
|
+
this.flights.set(request.id, { intent, target, result });
|
|
589
|
+
return result;
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
|
|
428
593
|
// src/workspace.ts
|
|
429
594
|
var ProjectOperationsApi = class {
|
|
430
595
|
constructor(mw) {
|
|
@@ -496,6 +661,7 @@ var WorkspaceCollection = class {
|
|
|
496
661
|
var WorkspaceApi = class {
|
|
497
662
|
constructor(mw) {
|
|
498
663
|
this.mw = mw;
|
|
664
|
+
this.sync = new ProjectSyncApi(mw);
|
|
499
665
|
this.git = new GitAccessApi(mw);
|
|
500
666
|
this.operations = new ProjectOperationsApi(mw);
|
|
501
667
|
this.agents = new WorkspaceCollection(mw, "agents");
|
|
@@ -503,6 +669,7 @@ var WorkspaceApi = class {
|
|
|
503
669
|
this.chats = new WorkspaceCollection(mw, "chats");
|
|
504
670
|
}
|
|
505
671
|
mw;
|
|
672
|
+
sync;
|
|
506
673
|
git;
|
|
507
674
|
operations;
|
|
508
675
|
agents;
|
|
@@ -511,6 +678,10 @@ var WorkspaceApi = class {
|
|
|
511
678
|
snapshot(options = {}) {
|
|
512
679
|
return this.mw.http.request("GET", "/workspace", { query: options });
|
|
513
680
|
}
|
|
681
|
+
/** Read the saved icon, or preview a candidate relative path within the project. Requires projectIconsVersion >= 1. */
|
|
682
|
+
projectIcon(projectId, path) {
|
|
683
|
+
return this.mw.http.request("GET", `/workspace/projects/${encodeURIComponent(projectId)}/icon`, { query: { path } });
|
|
684
|
+
}
|
|
514
685
|
/** Start an operation owned by the daemon. The same ID/payload returns the existing operation. */
|
|
515
686
|
createProject(request) {
|
|
516
687
|
return this.mw.http.request("POST", "/workspace/projects", { body: request });
|
|
@@ -567,7 +738,7 @@ var GitAccessApi = class {
|
|
|
567
738
|
run(projectId, operation, auth) {
|
|
568
739
|
return this.mw.http.request("POST", `/workspace/projects/${encodeURIComponent(projectId)}/git/${operation}`, { body: { auth } });
|
|
569
740
|
}
|
|
570
|
-
/** Requires health.gitOperationsVersion >= 1 (>= 2 for
|
|
741
|
+
/** Requires health.gitOperationsVersion >= 1 (>= 2 for switch/create, >= 4 for restore_commit, >= 5 for rename/delete). Acceptance persists before Git runs;
|
|
571
742
|
* disconnecting only detaches the client. The same ID/intent never runs twice.
|
|
572
743
|
*/
|
|
573
744
|
start(projectId, request) {
|
|
@@ -577,7 +748,7 @@ var GitAccessApi = class {
|
|
|
577
748
|
const result = await this.mw.http.request(
|
|
578
749
|
"GET",
|
|
579
750
|
`/workspace/projects/${encodeURIComponent(projectId)}/git/operations`,
|
|
580
|
-
{ query: { active: activeOnly, actionsVersion:
|
|
751
|
+
{ query: { active: activeOnly, actionsVersion: 5 } }
|
|
581
752
|
);
|
|
582
753
|
return result.operations;
|
|
583
754
|
}
|
|
@@ -831,7 +1002,7 @@ function computerPairingURI(invitation) {
|
|
|
831
1002
|
}
|
|
832
1003
|
|
|
833
1004
|
// src/version.ts
|
|
834
|
-
var SDK_VERSION = "0.1.
|
|
1005
|
+
var SDK_VERSION = "0.1.33" ;
|
|
835
1006
|
function versionAtLeast(actual, desired) {
|
|
836
1007
|
if (actual === desired) return true;
|
|
837
1008
|
if (!actual || !/^\d+\.\d+\.\d+$/.test(actual) || !/^\d+\.\d+\.\d+$/.test(desired)) return false;
|
|
@@ -2830,6 +3001,6 @@ function clearCatalogCache() {
|
|
|
2830
3001
|
inflight = null;
|
|
2831
3002
|
}
|
|
2832
3003
|
|
|
2833
|
-
export { AuthApi, ComputerApi, ContainerHost, ExecutionApi, GitAccessApi, Http, MODELS_DEV_URL, McpApi, Mindwire, NotifyApi, ProjectOperationsApi, PromptsApi, ProvidersApi, Run, SDK_VERSION, ServiceApi, SurfacesApi, TerminalsApi, WorkspaceApi, WorkspaceCollection, catalogModels, catalogProvider, catalogProviders, clearCatalogCache, computerPairingQRData, computerPairingURI, docker, ensureDaemon, ensureDaemonBinary, loadCatalog, local, lookupModel, oblien, provisionContainer, provisionDocker, provisionOblien, provisionSsh, provisionSshContainer, remote, resolveLinuxDaemon, ssh, startEmbedded };
|
|
3004
|
+
export { AuthApi, ComputerApi, ContainerHost, ExecutionApi, GitAccessApi, Http, MODELS_DEV_URL, McpApi, Mindwire, NotifyApi, ProjectOperationsApi, ProjectSyncApi, ProjectSyncError, PromptsApi, ProvidersApi, Run, SDK_VERSION, ServiceApi, SurfacesApi, TerminalsApi, WorkspaceApi, WorkspaceCollection, catalogModels, catalogProvider, catalogProviders, clearCatalogCache, computerPairingQRData, computerPairingURI, docker, ensureDaemon, ensureDaemonBinary, loadCatalog, local, lookupModel, oblien, provisionContainer, provisionDocker, provisionOblien, provisionSsh, provisionSshContainer, remote, resolveLinuxDaemon, ssh, startEmbedded };
|
|
2834
3005
|
//# sourceMappingURL=index.js.map
|
|
2835
3006
|
//# sourceMappingURL=index.js.map
|