@pstdio/pocketcoder-cli 0.6.1 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +171 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5214,7 +5214,7 @@ function isYargsInstance(y) {
|
|
|
5214
5214
|
var Yargs = YargsFactory(esm_default);
|
|
5215
5215
|
var yargs_default = Yargs;
|
|
5216
5216
|
// package.json
|
|
5217
|
-
var version = "0.6.
|
|
5217
|
+
var version = "0.6.2";
|
|
5218
5218
|
|
|
5219
5219
|
// src/cli-context.ts
|
|
5220
5220
|
import { existsSync as existsSync3, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
|
|
@@ -40637,6 +40637,172 @@ class PocketCoderClient {
|
|
|
40637
40637
|
return this.transport.raw(path, init);
|
|
40638
40638
|
}
|
|
40639
40639
|
}
|
|
40640
|
+
// ../sdk/src/workspace-turn-resolver.ts
|
|
40641
|
+
var ERROR_MESSAGES = {
|
|
40642
|
+
not_resumable: "workspace cannot be resumed",
|
|
40643
|
+
resume_handler_missing: "workspace resume handler is not configured",
|
|
40644
|
+
resume_failed: "workspace resume failed",
|
|
40645
|
+
invalid_resumed_workspace: "workspace resume returned an invalid workspace",
|
|
40646
|
+
readiness_failed: "resumed workspace did not become ready"
|
|
40647
|
+
};
|
|
40648
|
+
|
|
40649
|
+
class WorkspaceTurnResolutionError extends Error {
|
|
40650
|
+
code;
|
|
40651
|
+
constructor(code, cause) {
|
|
40652
|
+
super(ERROR_MESSAGES[code], cause === undefined ? undefined : { cause });
|
|
40653
|
+
this.name = "WorkspaceTurnResolutionError";
|
|
40654
|
+
this.code = code;
|
|
40655
|
+
}
|
|
40656
|
+
}
|
|
40657
|
+
var NON_RESUMABLE_STATES = new Set([
|
|
40658
|
+
"failed",
|
|
40659
|
+
"canceled",
|
|
40660
|
+
"expired",
|
|
40661
|
+
"succeeded",
|
|
40662
|
+
"terminating"
|
|
40663
|
+
]);
|
|
40664
|
+
function aborted2(signal) {
|
|
40665
|
+
return signal.reason ?? new DOMException("The operation was aborted", "AbortError");
|
|
40666
|
+
}
|
|
40667
|
+
function waitForCaller(promise2, signal) {
|
|
40668
|
+
if (!signal)
|
|
40669
|
+
return promise2;
|
|
40670
|
+
if (signal.aborted)
|
|
40671
|
+
return Promise.reject(aborted2(signal));
|
|
40672
|
+
return new Promise((resolve6, reject) => {
|
|
40673
|
+
const onAbort = () => reject(aborted2(signal));
|
|
40674
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
40675
|
+
promise2.then((value) => {
|
|
40676
|
+
signal.removeEventListener("abort", onAbort);
|
|
40677
|
+
resolve6(value);
|
|
40678
|
+
}, (error51) => {
|
|
40679
|
+
signal.removeEventListener("abort", onAbort);
|
|
40680
|
+
reject(error51);
|
|
40681
|
+
});
|
|
40682
|
+
});
|
|
40683
|
+
}
|
|
40684
|
+
function requireRemaining(deadline, failure) {
|
|
40685
|
+
const remaining = deadline - Date.now();
|
|
40686
|
+
if (remaining <= 0)
|
|
40687
|
+
throw new WorkspaceTurnResolutionError(failure);
|
|
40688
|
+
return remaining;
|
|
40689
|
+
}
|
|
40690
|
+
|
|
40691
|
+
class WorkspaceTurnResolver {
|
|
40692
|
+
client;
|
|
40693
|
+
resumeWorkspace;
|
|
40694
|
+
resumeTimeoutMs;
|
|
40695
|
+
attempts = new Map;
|
|
40696
|
+
constructor(options) {
|
|
40697
|
+
this.client = options.client;
|
|
40698
|
+
this.resumeWorkspace = options.resumeWorkspace;
|
|
40699
|
+
this.resumeTimeoutMs = options.resumeTimeoutMs ?? 300000;
|
|
40700
|
+
}
|
|
40701
|
+
async resolve(sourceWorkspaceId, options = {}) {
|
|
40702
|
+
if (options.signal?.aborted)
|
|
40703
|
+
throw aborted2(options.signal);
|
|
40704
|
+
const attempt = this.attempts.get(sourceWorkspaceId) ?? this.start(sourceWorkspaceId);
|
|
40705
|
+
attempt.waiters += 1;
|
|
40706
|
+
try {
|
|
40707
|
+
return await waitForCaller(attempt.promise, options.signal);
|
|
40708
|
+
} finally {
|
|
40709
|
+
attempt.waiters -= 1;
|
|
40710
|
+
if (attempt.waiters === 0 && !attempt.resumeStarted && !attempt.settled) {
|
|
40711
|
+
attempt.controller.abort(new DOMException("No callers remain", "AbortError"));
|
|
40712
|
+
}
|
|
40713
|
+
}
|
|
40714
|
+
}
|
|
40715
|
+
start(sourceWorkspaceId) {
|
|
40716
|
+
const attempt = {
|
|
40717
|
+
controller: new AbortController,
|
|
40718
|
+
promise: Promise.resolve(undefined),
|
|
40719
|
+
waiters: 0,
|
|
40720
|
+
resumeStarted: false,
|
|
40721
|
+
settled: false
|
|
40722
|
+
};
|
|
40723
|
+
this.attempts.set(sourceWorkspaceId, attempt);
|
|
40724
|
+
attempt.promise = this.run(sourceWorkspaceId, attempt).finally(() => {
|
|
40725
|
+
attempt.settled = true;
|
|
40726
|
+
if (this.attempts.get(sourceWorkspaceId) === attempt) {
|
|
40727
|
+
this.attempts.delete(sourceWorkspaceId);
|
|
40728
|
+
}
|
|
40729
|
+
});
|
|
40730
|
+
attempt.promise.catch(() => {});
|
|
40731
|
+
return attempt;
|
|
40732
|
+
}
|
|
40733
|
+
async run(sourceWorkspaceId, attempt) {
|
|
40734
|
+
const deadline = Date.now() + this.resumeTimeoutMs;
|
|
40735
|
+
let source = await this.client.workspaces.get(sourceWorkspaceId, {
|
|
40736
|
+
signal: attempt.controller.signal
|
|
40737
|
+
});
|
|
40738
|
+
if (source.state === "ready")
|
|
40739
|
+
return { workspace: source, resumed: false };
|
|
40740
|
+
if (source.state === "preserving") {
|
|
40741
|
+
source = await this.waitForPreserved(source, deadline, attempt.controller.signal);
|
|
40742
|
+
}
|
|
40743
|
+
this.assertResumable(source);
|
|
40744
|
+
if (!this.resumeWorkspace) {
|
|
40745
|
+
throw new WorkspaceTurnResolutionError("resume_handler_missing");
|
|
40746
|
+
}
|
|
40747
|
+
attempt.resumeStarted = true;
|
|
40748
|
+
const attemptId = crypto.randomUUID();
|
|
40749
|
+
let allocated;
|
|
40750
|
+
try {
|
|
40751
|
+
allocated = await this.resumeWorkspace({
|
|
40752
|
+
source,
|
|
40753
|
+
attemptId,
|
|
40754
|
+
signal: attempt.controller.signal
|
|
40755
|
+
});
|
|
40756
|
+
} catch (error51) {
|
|
40757
|
+
throw new WorkspaceTurnResolutionError("resume_failed", error51);
|
|
40758
|
+
}
|
|
40759
|
+
let fetched;
|
|
40760
|
+
try {
|
|
40761
|
+
fetched = await this.client.workspaces.get(allocated.id, {
|
|
40762
|
+
signal: attempt.controller.signal
|
|
40763
|
+
});
|
|
40764
|
+
} catch (error51) {
|
|
40765
|
+
throw new WorkspaceTurnResolutionError("invalid_resumed_workspace", error51);
|
|
40766
|
+
}
|
|
40767
|
+
this.assertLineage(source, fetched);
|
|
40768
|
+
try {
|
|
40769
|
+
const workspace = await this.client.workspaces.waitForReady(fetched, requireRemaining(deadline, "readiness_failed"), { signal: attempt.controller.signal });
|
|
40770
|
+
return { workspace, resumed: true };
|
|
40771
|
+
} catch (error51) {
|
|
40772
|
+
if (error51 instanceof WorkspaceTurnResolutionError)
|
|
40773
|
+
throw error51;
|
|
40774
|
+
throw new WorkspaceTurnResolutionError("readiness_failed", error51);
|
|
40775
|
+
}
|
|
40776
|
+
}
|
|
40777
|
+
async waitForPreserved(initial, deadline, signal) {
|
|
40778
|
+
let workspace = initial;
|
|
40779
|
+
while (workspace.state === "preserving") {
|
|
40780
|
+
const remaining = requireRemaining(deadline, "resume_failed");
|
|
40781
|
+
try {
|
|
40782
|
+
const change = await this.client.workspaces.change(workspace.id, workspace.change_cursor, Math.max(1, Math.min(30, Math.ceil(remaining / 1000))), { signal });
|
|
40783
|
+
workspace = change.workspace;
|
|
40784
|
+
} catch (error51) {
|
|
40785
|
+
if (signal.aborted)
|
|
40786
|
+
throw error51;
|
|
40787
|
+
throw new WorkspaceTurnResolutionError("resume_failed", error51);
|
|
40788
|
+
}
|
|
40789
|
+
}
|
|
40790
|
+
if (workspace.state === "failed") {
|
|
40791
|
+
throw new WorkspaceTurnResolutionError("resume_failed");
|
|
40792
|
+
}
|
|
40793
|
+
return workspace;
|
|
40794
|
+
}
|
|
40795
|
+
assertResumable(workspace) {
|
|
40796
|
+
if (workspace.state !== "preserved" || NON_RESUMABLE_STATES.has(workspace.state) || workspace.persistence.conversation_resume.status !== "supported" || !workspace.persistence.latest_checkpoint_id) {
|
|
40797
|
+
throw new WorkspaceTurnResolutionError("not_resumable");
|
|
40798
|
+
}
|
|
40799
|
+
}
|
|
40800
|
+
assertLineage(source, resumedWorkspace) {
|
|
40801
|
+
if (resumedWorkspace.id === source.id || resumedWorkspace.origin_workspace_id !== source.id || resumedWorkspace.restored_from_checkpoint_id !== source.persistence.latest_checkpoint_id) {
|
|
40802
|
+
throw new WorkspaceTurnResolutionError("invalid_resumed_workspace");
|
|
40803
|
+
}
|
|
40804
|
+
}
|
|
40805
|
+
}
|
|
40640
40806
|
// src/cli-context.ts
|
|
40641
40807
|
var import_dotenv = __toESM(require_main(), 1);
|
|
40642
40808
|
function need(flags, key) {
|
|
@@ -43101,9 +43267,9 @@ class FilesystemStorageDriver {
|
|
|
43101
43267
|
}
|
|
43102
43268
|
}
|
|
43103
43269
|
async initRoots() {
|
|
43104
|
-
await mkdir3(this.workspaceRoot, { recursive: true, mode:
|
|
43270
|
+
await mkdir3(this.workspaceRoot, { recursive: true, mode: 457 });
|
|
43105
43271
|
await mkdir3(this.checkpointRoot, { recursive: true, mode: 448 });
|
|
43106
|
-
await chmod3(this.workspaceRoot,
|
|
43272
|
+
await chmod3(this.workspaceRoot, 457);
|
|
43107
43273
|
await chmod3(this.checkpointRoot, 448);
|
|
43108
43274
|
}
|
|
43109
43275
|
storageRef(ref) {
|
|
@@ -43123,8 +43289,8 @@ class FilesystemStorageDriver {
|
|
|
43123
43289
|
async allocate(input) {
|
|
43124
43290
|
await this.initRoots();
|
|
43125
43291
|
const root = childOf2(this.workspaceRoot, input.storageId);
|
|
43126
|
-
await mkdir3(root, { recursive: true, mode:
|
|
43127
|
-
await chmod3(root,
|
|
43292
|
+
await mkdir3(root, { recursive: true, mode: 457 });
|
|
43293
|
+
await chmod3(root, 457);
|
|
43128
43294
|
for (const mount of input.mounts) {
|
|
43129
43295
|
const path = join7(root, mount.name);
|
|
43130
43296
|
await mkdir3(path, { recursive: true, mode: 504 });
|