@playcraft/cli 0.1.22 → 0.1.23

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.
@@ -513,12 +513,15 @@ export function createCodexAppServerAdapter(options) {
513
513
  },
514
514
  async interrupt(input) {
515
515
  await ensureStarted();
516
+ const thread = threads.get(input.threadId);
517
+ // Nothing is sent when no turn of this session runs here, so that answer is definite.
518
+ if (thread?.sessionId !== input.sessionId || !thread.turnActive)
519
+ return { outcome: 'failed', error: 'turn_not_running' };
516
520
  if (!rpc)
517
521
  return { outcome: 'uncertain' };
518
- if (threads.get(input.threadId)?.sessionId !== input.sessionId)
519
- return { outcome: 'uncertain' };
520
- const turnId = threads.get(input.threadId)?.lastTurnId;
521
- if (!turnId)
522
+ const turnId = thread.lastTurnId;
523
+ // A turn that is still starting has no id yet; the last one is already over.
524
+ if (!turnId || turnId === thread.lastCompletedTurnId)
522
525
  return { outcome: 'uncertain' };
523
526
  try {
524
527
  await rpc.request('turn/interrupt', { threadId: input.threadId, turnId });
@@ -364,6 +364,9 @@ async function executeInterrupt(state, scopeKey, operation) {
364
364
  return persist(state, scopeKey, transitionOperation(operation, 'failed', { error: 'unknown_session' }));
365
365
  }
366
366
  const result = await native(state).interrupt({ sessionId, threadId: binding.threadId });
367
+ if (result.outcome === 'failed') {
368
+ return persist(state, scopeKey, transitionOperation(operation, 'failed', { error: result.error ?? 'turn_not_running' }));
369
+ }
367
370
  if (result.outcome !== 'accepted') {
368
371
  return persist(state, scopeKey, transitionOperation(operation, 'uncertain', { error: 'native_receipt_lost' }));
369
372
  }
@@ -1,7 +1,7 @@
1
1
  import { readObservedFile, withObservedFile } from '../workspaces/revisions.js';
2
2
  import { registerWorkspace, revisionScope, sessionWorkspaceRoot, workspaceRoot, WorkspaceContextError } from '../workspaces/registry.js';
3
3
  import { randomUUID } from 'node:crypto';
4
- import { workspaceRegistrationRequestSchema, HTTP_STATUS_BY_ERROR, assertLeaseFence, buildHandshakeDocument, capability, findUntrustedRuntimeFields, gitFileRefSchema, hashOperationPayload, isLostThreadError, sourceAckSchema, operationAcceptRequestSchema, operationKindSchema, operationScopeKey, resolveIdempotentAccept, nativeHistoryReadSchema, runtimeError, runtimeConnectivityDocumentSchema, unavailableRuntimeCapabilities, } from '@playcraft/common/cloud-workspace/runtime';
4
+ import { workspaceRegistrationRequestSchema, HTTP_STATUS_BY_ERROR, assertLeaseFence, buildHandshakeDocument, capability, findUntrustedRuntimeFields, gitFileRefSchema, hashOperationPayload, isLostThreadError, sourceAckSchema, operationAcceptRequestSchema, operationKindSchema, operationScopeKey, isWorkspaceMutation, resolveIdempotentAccept, nativeHistoryReadSchema, runtimeError, runtimeConnectivityDocumentSchema, unavailableRuntimeCapabilities, } from '@playcraft/common/cloud-workspace/runtime';
5
5
  import { controlTokenMatches, extractControlToken } from './auth.js';
6
6
  import { applyRuntimeEndpointPatch } from './endpoints.js';
7
7
  import { canExecuteKind, executeOperation } from './dispatch.js';
@@ -418,7 +418,7 @@ async function acceptOperation(state, request, response) {
418
418
  await restoreWorkspaceDirectory(state, parsed.data.workspaceId, parsed.data.directoryName);
419
419
  if (state.config.workspaceMode === 'multi')
420
420
  await sessionWorkspaceRoot(state, parsed.data.workspaceId, parsed.data.directoryName);
421
- const mutation = !['runtime.ensure', 'runtime.destroy', 'session.interrupt', 'session.approval.respond'].includes(parsed.data.kind);
421
+ const mutation = isWorkspaceMutation(parsed.data.kind);
422
422
  if (mutation && await productionDirectoryBusy(state, parsed.data.workspaceId, parsed.data.directoryName)) {
423
423
  writeJson(response, 409, { error: 'batch_workspace_readonly' });
424
424
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playcraft/cli",
3
- "version": "0.1.22",
3
+ "version": "0.1.23",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "engines": {
@@ -48,8 +48,8 @@
48
48
  "@gltf-transform/core": "^4.3.0",
49
49
  "@gltf-transform/extensions": "^4.3.0",
50
50
  "@gltf-transform/functions": "^4.3.0",
51
- "@playcraft/build": "^0.1.22",
52
- "@playcraft/common": "^0.1.22",
51
+ "@playcraft/build": "^0.1.23",
52
+ "@playcraft/common": "^0.1.23",
53
53
  "better-sqlite3-pinned": "npm:better-sqlite3@13.0.3",
54
54
  "chokidar": "^4.0.3",
55
55
  "commander": "^13.1.0",