@playcraft/cli 0.1.57-beta → 0.1.58-beta
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/commands/workspace.js +43 -0
- package/dist/workspace/messages.js +10 -0
- package/dist/workspace-runtime/batch/deliver.js +140 -80
- package/dist/workspace-runtime/batch/freeze.js +18 -6
- package/dist/workspace-runtime/batch/generate.js +68 -64
- package/dist/workspace-runtime/batch/prepare.js +108 -93
- package/dist/workspace-runtime/batch/records.js +4 -0
- package/dist/workspace-runtime/batch/routes.js +10 -2
- package/dist/workspace-runtime/batch/source-candidate.js +2 -0
- package/dist/workspace-runtime/batch/source-capture.js +1 -0
- package/dist/workspace-runtime/batch/source-failure.js +2 -0
- package/dist/workspace-runtime/batch/source-publish.js +3 -0
- package/dist/workspace-runtime/batch/writer-proof.js +37 -0
- package/dist/workspace-runtime/codex/app-server.js +1 -0
- package/dist/workspace-runtime/codex/config-toml.js +4 -0
- package/dist/workspace-runtime/codex/delivery-tools.js +1 -1
- package/dist/workspace-runtime/persistence/journal.js +34 -0
- package/dist/workspace-runtime/persistence/sqlite-worker.js +68 -6
- package/dist/workspace-runtime/previews/output.js +2 -0
- package/dist/workspace-runtime/previews/publish.js +20 -5
- package/dist/workspace-runtime/previews/runtime-preview.js +4 -0
- package/dist/workspace-runtime/processes/managed-writes.js +47 -5
- package/dist/workspace-runtime/serve.js +11 -2
- package/dist/workspace-runtime/server/accept-operation.js +22 -2
- package/dist/workspace-runtime/server/directory-access.js +414 -0
- package/dist/workspace-runtime/server/dispatch.js +61 -23
- package/dist/workspace-runtime/server/endpoints.js +1 -0
- package/dist/workspace-runtime/server/http.js +52 -10
- package/dist/workspace-runtime/server/operation-record.js +2 -0
- package/dist/workspace-runtime/server/terminal-host.js +43 -8
- package/dist/workspace-runtime/server/workspace-transfer.js +3 -1
- package/dist/workspace-runtime/workspaces/append-only-log.js +3 -0
- package/dist/workspace-runtime/workspaces/artifact-events.js +5 -2
- package/dist/workspace-runtime/workspaces/artifact-files.js +14 -8
- package/dist/workspace-runtime/workspaces/artifact-receipts.js +7 -25
- package/dist/workspace-runtime/workspaces/artifacts.js +4 -1
- package/dist/workspace-runtime/workspaces/asset-library-import.js +9 -4
- package/dist/workspace-runtime/workspaces/asset-publication-access.js +7 -9
- package/dist/workspace-runtime/workspaces/asset-transfer-publish.js +3 -0
- package/dist/workspace-runtime/workspaces/asset-transfer-storage.js +17 -2
- package/dist/workspace-runtime/workspaces/attachments.js +9 -0
- package/dist/workspace-runtime/workspaces/batch-commit.js +5 -3
- package/dist/workspace-runtime/workspaces/binary-write.js +12 -7
- package/dist/workspace-runtime/workspaces/cli-context.js +2 -0
- package/dist/workspace-runtime/workspaces/cli-credentials.js +1 -0
- package/dist/workspace-runtime/workspaces/delivery-build.js +30 -11
- package/dist/workspace-runtime/workspaces/delivery-store.js +2 -0
- package/dist/workspace-runtime/workspaces/dependencies.js +90 -70
- package/dist/workspace-runtime/workspaces/developer-command.js +12 -1
- package/dist/workspace-runtime/workspaces/directory-access.js +13 -18
- package/dist/workspace-runtime/workspaces/directory-attachments.js +8 -0
- package/dist/workspace-runtime/workspaces/directory-create.js +18 -5
- package/dist/workspace-runtime/workspaces/directory-maintenance.js +46 -35
- package/dist/workspace-runtime/workspaces/directory-mutations.js +8 -3
- package/dist/workspace-runtime/workspaces/files.js +4 -0
- package/dist/workspace-runtime/workspaces/git-credential-broker.js +3 -0
- package/dist/workspace-runtime/workspaces/git-direct-store.js +2 -0
- package/dist/workspace-runtime/workspaces/json5-edit.js +36 -0
- package/dist/workspace-runtime/workspaces/library-attachments.js +4 -0
- package/dist/workspace-runtime/workspaces/parameter-agent-protocol.js +2 -0
- package/dist/workspace-runtime/workspaces/parameter-agent-store.js +2 -0
- package/dist/workspace-runtime/workspaces/parameter-agent.js +40 -11
- package/dist/workspace-runtime/workspaces/parameter-assets.js +1 -0
- package/dist/workspace-runtime/workspaces/parameter-initialization-skill-transaction.js +141 -0
- package/dist/workspace-runtime/workspaces/parameter-initialization-skill.js +329 -0
- package/dist/workspace-runtime/workspaces/parameter-initialization.js +63 -0
- package/dist/workspace-runtime/workspaces/parameter-production.js +124 -0
- package/dist/workspace-runtime/workspaces/parameters.js +95 -3
- package/dist/workspace-runtime/workspaces/platform-export.js +5 -0
- package/dist/workspace-runtime/workspaces/prepare.js +4 -0
- package/dist/workspace-runtime/workspaces/registry.js +11 -0
- package/dist/workspace-runtime/workspaces/remix-references.js +5 -0
- package/dist/workspace-runtime/workspaces/shared-write.js +187 -0
- package/dist/workspace-runtime/workspaces/skills.js +14 -15
- package/dist/workspace-runtime/workspaces/transfer.js +4 -1
- package/dist/workspace-runtime/workspaces/workspace-shares.js +235 -0
- package/dist/workspace-runtime/workspaces/worktree-attachments.js +2 -0
- package/dist/workspace-runtime/workspaces/worktree-checkout.js +11 -6
- package/package.json +5 -4
- package/project-template/.claude/skills/playcraft-runtime-parameters/SKILL.md +32 -0
- package/project-template/.claude/skills/playcraft-runtime-parameters/references/platform-protocol.md +21 -0
- package/project-template/.claude/skills/playcraft-runtime-parameters/references/preview-integration.md +57 -0
|
@@ -17,6 +17,7 @@ import { openScratchToDevelopment } from '../workspaces/directory-access.js';
|
|
|
17
17
|
import { injectPreviewDiagnostics } from './diagnostics.js';
|
|
18
18
|
import { OperationLogStore } from '../workspaces/operation-log.js';
|
|
19
19
|
import { prepareRuntimePreview, RuntimePreviewBuildError } from './runtime-preview.js';
|
|
20
|
+
import { driftScope, permissionDriftFromOutput, repairWorkspaceShares, } from '../workspaces/workspace-shares.js';
|
|
20
21
|
const BUILD_TIMEOUT_MS = 10 * 60_000;
|
|
21
22
|
/** Build output and the builder's own scratch folder live in the checkout, hidden from Git. */
|
|
22
23
|
const OUTPUT_FOLDER = '.playcraft-preview-out';
|
|
@@ -60,12 +61,12 @@ export function trackPreviewPublish(state, task) {
|
|
|
60
61
|
export async function settlePreviewPublishes(state) {
|
|
61
62
|
await Promise.all([...(running.get(state) ?? [])]);
|
|
62
63
|
}
|
|
63
|
-
/**
|
|
64
|
+
/** Restart alone does not prove the old builder stopped; retain its exclusive directory claim. */
|
|
64
65
|
export async function recoverInterruptedPreviews(journal) {
|
|
65
66
|
for (const { scopeKey, operation } of journal.listOperations()) {
|
|
66
67
|
if (operation.kind !== 'preview.publish' || operation.status !== 'accepted')
|
|
67
68
|
continue;
|
|
68
|
-
await journal.putOperation(scopeKey, transitionOperation(operation, '
|
|
69
|
+
await journal.putOperation(scopeKey, transitionOperation(operation, 'uncertain', { error: 'preview_interrupted' }));
|
|
69
70
|
}
|
|
70
71
|
}
|
|
71
72
|
export async function runPreviewPublish(state, operation, root) {
|
|
@@ -215,7 +216,7 @@ async function ensureDependencies(state, workspaceId, root, output) {
|
|
|
215
216
|
async function buildPreview(state, root, outputDir, operationId, output, onLog, runtimeCommand) {
|
|
216
217
|
// Tests replace the build; the real one needs a project and the published CLI.
|
|
217
218
|
const planned = process.env.PLAYCRAFT_PREVIEW_BUILD_COMMAND || BUILD_COMMAND;
|
|
218
|
-
const
|
|
219
|
+
const run = () => runDeveloperCommand(state, {
|
|
219
220
|
processId: `preview-${operationId}`,
|
|
220
221
|
cwd: root,
|
|
221
222
|
command: runtimeCommand ?? `${planned} --output ${shellQuote(outputDir)} .`,
|
|
@@ -226,8 +227,22 @@ async function buildPreview(state, root, outputDir, operationId, output, onLog,
|
|
|
226
227
|
onLog?.(text);
|
|
227
228
|
},
|
|
228
229
|
});
|
|
229
|
-
|
|
230
|
-
|
|
230
|
+
let outcome = await run();
|
|
231
|
+
if (outcome.code === undefined)
|
|
232
|
+
throw new PreviewFailure('preview_process_unknown');
|
|
233
|
+
if (outcome.code !== 0) {
|
|
234
|
+
// The build runs as the development identity; a directory only that identity can repair makes
|
|
235
|
+
// it fail on its own cwd. Repair the shared subtree as its owner and retry exactly once.
|
|
236
|
+
const drift = permissionDriftFromOutput(output.log);
|
|
237
|
+
if (drift) {
|
|
238
|
+
await repairWorkspaceShares(state, root, await driftScope(root, drift.path)).catch(() => undefined);
|
|
239
|
+
outcome = await run();
|
|
240
|
+
if (outcome.code === undefined)
|
|
241
|
+
throw new PreviewFailure('preview_process_unknown');
|
|
242
|
+
}
|
|
243
|
+
if (outcome.code !== 0)
|
|
244
|
+
throw new PreviewFailure(drift ? 'workspace_permission_drift' : 'preview_build_failed');
|
|
245
|
+
}
|
|
231
246
|
}
|
|
232
247
|
/** Reads the one HTML file without following links, so the uploaded bytes are what was checked. */
|
|
233
248
|
async function readSingleHtml(outputDir) {
|
|
@@ -166,6 +166,8 @@ export async function prepareRuntimePreview(state, operation, root) {
|
|
|
166
166
|
dataRevision: before.dataRevision ?? 0,
|
|
167
167
|
schemaRevision: before.schemaRevision ?? 0,
|
|
168
168
|
dataHash: before.dataHash,
|
|
169
|
+
...(before.runtimeI18n ? { runtimeI18nRevision: before.runtimeI18n.themeRevision,
|
|
170
|
+
...(before.runtimeI18n.themeHash ? { runtimeI18nHash: before.runtimeI18n.themeHash } : {}) } : {}),
|
|
169
171
|
},
|
|
170
172
|
};
|
|
171
173
|
const context = { buildId, ...profileBase };
|
|
@@ -187,6 +189,8 @@ export async function prepareRuntimePreview(state, operation, root) {
|
|
|
187
189
|
after.schemaHash !== before.schemaHash ||
|
|
188
190
|
after.dataRevision !== before.dataRevision ||
|
|
189
191
|
after.schemaRevision !== before.schemaRevision ||
|
|
192
|
+
after.runtimeI18n?.themeHash !== before.runtimeI18n?.themeHash ||
|
|
193
|
+
after.runtimeI18n?.themeRevision !== before.runtimeI18n?.themeRevision ||
|
|
190
194
|
digest(await insideFile(root, manifestPath)) !== digest(manifest))
|
|
191
195
|
throw new RuntimePreviewBuildError('runtime_preview_source_changed');
|
|
192
196
|
for (const [path, hash] of gameHashes) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { setTimeout as delay } from 'node:timers/promises';
|
|
3
|
+
import { holdDirectoryAccess, managedDirectoryScope } from '../server/directory-access.js';
|
|
3
4
|
export const MANAGED_WRITE_SOURCES = ['manual', 'agent', 'background'];
|
|
4
5
|
const BACKGROUND_WRITER = `
|
|
5
6
|
const fs = require('node:fs');
|
|
@@ -23,16 +24,48 @@ export function probeProcess(pid) {
|
|
|
23
24
|
return undefined;
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
|
-
export function spawnBackgroundWriter(absolutePath) {
|
|
27
|
+
export function spawnBackgroundWriter(absolutePath, stopped) {
|
|
27
28
|
const child = spawn(process.execPath, ['-e', BACKGROUND_WRITER, absolutePath], {
|
|
28
29
|
detached: true,
|
|
29
30
|
stdio: 'ignore',
|
|
30
31
|
});
|
|
31
32
|
child.unref();
|
|
33
|
+
child.once('error', () => undefined);
|
|
34
|
+
child.once('exit', () => stopped?.());
|
|
32
35
|
if (!child.pid)
|
|
33
36
|
throw new Error('background_write_failed');
|
|
34
37
|
return child.pid;
|
|
35
38
|
}
|
|
39
|
+
/** A writer keeps its directory claim after the request that created it has finished. */
|
|
40
|
+
export async function startManagedBackgroundWriter(state, record, absolutePath) {
|
|
41
|
+
if (state.journal.listManagedWrites().some(item => item.writeId === record.writeId && !item.stoppedAt))
|
|
42
|
+
throw new Error('write_already_active');
|
|
43
|
+
const release = await holdDirectoryAccess(state, managedDirectoryScope(state, record.workspaceId), `managed:${record.writeId}`, 'shared');
|
|
44
|
+
let pid;
|
|
45
|
+
let persisted = Promise.resolve();
|
|
46
|
+
const finish = async () => {
|
|
47
|
+
await persisted;
|
|
48
|
+
const current = state.journal.listManagedWrites().find(item => item.writeId === record.writeId);
|
|
49
|
+
if (current && current.startedAt === record.startedAt && !current.stoppedAt) {
|
|
50
|
+
await state.journal.putManagedWrite({ ...current, stoppedAt: new Date().toISOString() });
|
|
51
|
+
}
|
|
52
|
+
release();
|
|
53
|
+
};
|
|
54
|
+
try {
|
|
55
|
+
await state.journal.putManagedWrite(record);
|
|
56
|
+
pid = spawnBackgroundWriter(absolutePath, () => { void finish().catch(() => undefined); });
|
|
57
|
+
persisted = state.journal.putManagedWrite({ ...record, pid });
|
|
58
|
+
await persisted;
|
|
59
|
+
return pid;
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
if (pid === undefined || await stopBackgroundWriter(pid)) {
|
|
63
|
+
persisted = Promise.resolve();
|
|
64
|
+
await finish();
|
|
65
|
+
}
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
36
69
|
export async function stopBackgroundWriter(pid) {
|
|
37
70
|
signal(pid, 'SIGTERM');
|
|
38
71
|
if (await waitUntilStopped(pid, 2_000))
|
|
@@ -58,12 +91,21 @@ function signal(pid, name) {
|
|
|
58
91
|
async function waitUntilStopped(pid, timeoutMs) {
|
|
59
92
|
const deadline = Date.now() + timeoutMs;
|
|
60
93
|
while (Date.now() < deadline) {
|
|
61
|
-
const alive =
|
|
94
|
+
const alive = probeProcessGroup(pid);
|
|
62
95
|
if (alive === false)
|
|
63
96
|
return true;
|
|
64
|
-
if (alive === undefined)
|
|
65
|
-
return false;
|
|
66
97
|
await delay(50);
|
|
67
98
|
}
|
|
68
|
-
return
|
|
99
|
+
return probeProcessGroup(pid) === false;
|
|
100
|
+
}
|
|
101
|
+
function probeProcessGroup(pid) {
|
|
102
|
+
try {
|
|
103
|
+
process.kill(-pid, 0);
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
if (error.code !== 'ESRCH')
|
|
108
|
+
return undefined;
|
|
109
|
+
return probeProcess(pid);
|
|
110
|
+
}
|
|
69
111
|
}
|
|
@@ -8,7 +8,8 @@ import { createCodexAppServerAdapter } from './codex/app-server.js';
|
|
|
8
8
|
import { trustedMemberPolicy } from './batch/policy.js';
|
|
9
9
|
import { batchDirectoryHeld } from './batch/occupancy.js';
|
|
10
10
|
import { createLoopbackNativeAdapter } from './codex/loopback.js';
|
|
11
|
-
import { attachNativeCollector, recoverInterruptedParameterVerifications, stopParameterVerifications } from './server/dispatch.js';
|
|
11
|
+
import { attachNativeCollector, executeOperation, recoverInterruptedParameterVerifications, stopParameterVerifications } from './server/dispatch.js';
|
|
12
|
+
import { restoreDeferredDirectoryOperations } from './server/directory-access.js';
|
|
12
13
|
import { handleRuntimeRequest } from './server/http.js';
|
|
13
14
|
import { desktopHost, disposeDesktopHost } from './server/desktop-host.js';
|
|
14
15
|
import { disposeTerminalHost, terminalHost } from './server/terminal-host.js';
|
|
@@ -57,7 +58,8 @@ export async function startWorkspaceRuntime(config, options = {}) {
|
|
|
57
58
|
await recoverInterruptedPreviews(journal);
|
|
58
59
|
await recoverInterruptedParameterVerifications(journal);
|
|
59
60
|
await recoverInterruptedDeliveries(config.stateDir);
|
|
60
|
-
|
|
61
|
+
// shared: in multi-workspace mode this is /workspaces, the container both identities traverse.
|
|
62
|
+
await mkdir(config.workspaceRoot, { recursive: true, mode: 0o2770 });
|
|
61
63
|
const state = runtimeState = {
|
|
62
64
|
config: { ...config, protocolMinor: negotiated.protocolMinor },
|
|
63
65
|
configPath: options.configPath,
|
|
@@ -99,6 +101,8 @@ export async function startWorkspaceRuntime(config, options = {}) {
|
|
|
99
101
|
for (const { scopeKey, operation } of journal.listOperations()) {
|
|
100
102
|
if (operation.kind !== 'asset.library.import' || !['queued', 'dispatched', 'accepted', 'uncertain'].includes(operation.status))
|
|
101
103
|
continue;
|
|
104
|
+
if (operation.status === 'queued' && journal.deferredDirectoryOperations().some(item => item.operationId === operation.operationId))
|
|
105
|
+
continue;
|
|
102
106
|
const published = recoveredImports.get(operation.operationId);
|
|
103
107
|
const result = operation.result && 'paths' in operation.result ? { ...operation.result,
|
|
104
108
|
paths: [...new Set([...operation.result.paths, ...(published?.paths ?? [])])],
|
|
@@ -150,6 +154,8 @@ export async function startWorkspaceRuntime(config, options = {}) {
|
|
|
150
154
|
for (const { scopeKey, operation } of journal.listOperations()) {
|
|
151
155
|
if (operation.kind !== 'asset.bundle.save' || !['queued', 'dispatched', 'accepted', 'uncertain'].includes(operation.status))
|
|
152
156
|
continue;
|
|
157
|
+
if (operation.status === 'queued' && journal.deferredDirectoryOperations().some(item => item.operationId === operation.operationId))
|
|
158
|
+
continue;
|
|
153
159
|
const recovered = recoveredBundles.get(operation.operationId), receipt = recovered?.receipt;
|
|
154
160
|
let next = operation;
|
|
155
161
|
if (receipt) {
|
|
@@ -181,6 +187,8 @@ export async function startWorkspaceRuntime(config, options = {}) {
|
|
|
181
187
|
if (!['directory.rename', 'directory.delete'].includes(operation.kind)
|
|
182
188
|
|| !['queued', 'dispatched', 'accepted', 'uncertain'].includes(operation.status))
|
|
183
189
|
continue;
|
|
190
|
+
if (operation.status === 'queued' && journal.deferredDirectoryOperations().some(item => item.operationId === operation.operationId))
|
|
191
|
+
continue;
|
|
184
192
|
const kind = operation.kind;
|
|
185
193
|
let next = operation;
|
|
186
194
|
try {
|
|
@@ -272,6 +280,7 @@ export async function startWorkspaceRuntime(config, options = {}) {
|
|
|
272
280
|
state.nativeError = code === 'codex_model_catalog_unavailable' ? code : 'codex_start_failed';
|
|
273
281
|
console.error(`[workspace-runtime] ${state.nativeError}`);
|
|
274
282
|
}
|
|
283
|
+
await restoreDeferredDirectoryOperations(state, (scopeKey, operation, payload, recovery) => executeOperation(state, scopeKey, operation, payload, recovery));
|
|
275
284
|
const server = createServer((request, response) => {
|
|
276
285
|
void handleRuntimeRequest(state, request, response);
|
|
277
286
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { assertLeaseFence, hashOperationPayload, isLostThreadError, operationScopeKey, resolveIdempotentAccept, runtimeError, } from '@playcraft/common/cloud-workspace/runtime';
|
|
1
|
+
import { assertLeaseFence, hashOperationPayload, isLostThreadError, operationScopeKey, resolveIdempotentAccept, runtimeError, takesWorkspaceDirectory, isTurnControl, } from '@playcraft/common/cloud-workspace/runtime';
|
|
2
2
|
import { canExecuteKind, executeOperation } from './dispatch.js';
|
|
3
3
|
import { buildOperationRecord } from './operation-record.js';
|
|
4
4
|
/**
|
|
@@ -29,6 +29,18 @@ export async function acceptOperationCore(state, parsed, options) {
|
|
|
29
29
|
operationId: decision.operation.operationId,
|
|
30
30
|
}));
|
|
31
31
|
}
|
|
32
|
+
if (decision.action === 'reuse' && parsed.gatewayOperationId) {
|
|
33
|
+
if (decision.operation.gatewayOperationId && decision.operation.gatewayOperationId !== parsed.gatewayOperationId) {
|
|
34
|
+
return rejected(409, runtimeError('idempotency_conflict', 'gateway_operation_mismatch', {
|
|
35
|
+
operationId: decision.operation.operationId,
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
38
|
+
if (!decision.operation.gatewayOperationId) {
|
|
39
|
+
decision.operation = await state.journal.putOperation(scopeKey, {
|
|
40
|
+
...decision.operation, gatewayOperationId: parsed.gatewayOperationId,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
32
44
|
const retryWithRecovery = decision.action === 'reuse' && parsed.kind === 'session.turn'
|
|
33
45
|
&& Boolean(parsed.sessionRecovery) && decision.operation.status === 'failed'
|
|
34
46
|
&& isLostThreadError(decision.operation.error);
|
|
@@ -38,6 +50,12 @@ export async function acceptOperationCore(state, parsed, options) {
|
|
|
38
50
|
operationId: decision.operation.operationId,
|
|
39
51
|
}));
|
|
40
52
|
}
|
|
53
|
+
if (decision.operation.status === 'queued' && takesWorkspaceDirectory(decision.operation.kind) &&
|
|
54
|
+
!isTurnControl(decision.operation.kind) && !state.journal.deferredDirectoryOperations().some(item => item.operationId === decision.operation.operationId)) {
|
|
55
|
+
const queued = await state.journal.putPendingOperation(scopeKey, decision.operation, options.executionPayload, parsed.sessionRecovery);
|
|
56
|
+
const executed = await executeOperation(state, scopeKey, queued, options.executionPayload, parsed.sessionRecovery);
|
|
57
|
+
return { rejected: false, operation: executed, executed, reused: true };
|
|
58
|
+
}
|
|
41
59
|
return { rejected: false, operation: decision.operation, executed: decision.operation, reused: true };
|
|
42
60
|
}
|
|
43
61
|
const validation = await options.validate?.(scopeKey);
|
|
@@ -51,7 +69,9 @@ export async function acceptOperationCore(state, parsed, options) {
|
|
|
51
69
|
}
|
|
52
70
|
state.acceptedLeaseFence = Math.max(state.acceptedLeaseFence, options.leaseFence);
|
|
53
71
|
await state.journal.setAcceptedLeaseFence(state.acceptedLeaseFence);
|
|
54
|
-
const queued =
|
|
72
|
+
const queued = takesWorkspaceDirectory(operation.kind) && !isTurnControl(operation.kind) && operation.kind !== 'runtime.destroy'
|
|
73
|
+
? await state.journal.putPendingOperation(scopeKey, operation, options.executionPayload, parsed.sessionRecovery)
|
|
74
|
+
: await state.journal.putOperation(scopeKey, operation);
|
|
55
75
|
const executed = await executeOperation(state, scopeKey, queued, options.executionPayload, parsed.sessionRecovery);
|
|
56
76
|
return { rejected: false, operation: queued, executed, reused: false };
|
|
57
77
|
});
|