@skaile/workspaces 0.11.1 → 0.12.0

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.
Files changed (31) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/base-assets/connectors/flow/run-flow.js +1 -1
  3. package/dist/bridge/drivers/claude-sdk.js +31 -28
  4. package/dist/bridge/drivers/claude-sdk.js.map +1 -1
  5. package/dist/bridge/drivers/codex.js +1 -1
  6. package/dist/bridge/drivers/echo.js +1 -1
  7. package/dist/bridge/drivers/omp.js +1 -1
  8. package/dist/bridge/index.js +3 -3
  9. package/dist/bridge/src/drivers/claude-sdk.d.ts +33 -17
  10. package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -1
  11. package/dist/bridge/src/error-classifier.d.ts.map +1 -1
  12. package/dist/{chunk-YOFKTALB.js → chunk-4ACWI5YT.js} +2 -2
  13. package/dist/{chunk-YOFKTALB.js.map → chunk-4ACWI5YT.js.map} +1 -1
  14. package/dist/{chunk-XYEFV7XN.js → chunk-DDVKNST3.js} +2 -2
  15. package/dist/{chunk-XYEFV7XN.js.map → chunk-DDVKNST3.js.map} +1 -1
  16. package/dist/{chunk-EWP5HZBV.js → chunk-DQWREFRQ.js} +11 -2
  17. package/dist/chunk-DQWREFRQ.js.map +1 -0
  18. package/dist/{chunk-VMU2WEN7.js → chunk-S2OVTCAL.js} +4 -4
  19. package/dist/{chunk-VMU2WEN7.js.map → chunk-S2OVTCAL.js.map} +1 -1
  20. package/dist/{chunk-34333Z5H.js → chunk-UTKGPNLV.js} +5 -5
  21. package/dist/{chunk-34333Z5H.js.map → chunk-UTKGPNLV.js.map} +1 -1
  22. package/dist/cli/index.js +6 -6
  23. package/dist/runner/index.js +4 -4
  24. package/dist/sdk/bridge.js +3 -3
  25. package/dist/sdk/index.js +4 -4
  26. package/dist/sdk/runner.js +4 -4
  27. package/dist/{setup-QAOUBECX.js → setup-WZFCLQ2J.js} +5 -5
  28. package/dist/{setup-QAOUBECX.js.map → setup-WZFCLQ2J.js.map} +1 -1
  29. package/dist/tui/index.js +4 -4
  30. package/package.json +14 -15
  31. package/dist/chunk-EWP5HZBV.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,42 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.12.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#21](https://github.com/skaile-ai/workspaces/pull/21) [`e06401f`](https://github.com/skaile-ai/workspaces/commit/e06401f771ac58b484ccbf7e465d3048e7e7a70d) Thanks [@peteralbert](https://github.com/peteralbert)! - Dependency upgrades.
8
+
9
+ - **Optional peer ranges raised** (consumers using these drivers should move to the new ranges): `@anthropic-ai/claude-agent-sdk` `^0.2.89` → `^0.3.150`, `@openai/codex-sdk` `^0.118.0` → `^0.133.0`. No driver code changes were required — the used API surface is unchanged.
10
+ - **Runtime dependencies bumped:** `commander` 13 → 14, `@clack/prompts` 0.9 → 1.4, `ulid` 2 → 3, `@octokit/rest` → 22.0.1, `semver` → 7.8.1, `ws` → 8.21.0. No source changes needed.
11
+
12
+ `marked` is intentionally held at 15.x — it is capped by `marked-terminal`'s peer range (`>=1 <16`) until an upstream release lifts it.
13
+
14
+ ### Patch Changes
15
+
16
+ - [#20](https://github.com/skaile-ai/workspaces/pull/20) [`843b611`](https://github.com/skaile-ai/workspaces/commit/843b6113075e6ecfd041d66ff161357f5eca1fb6) Thanks [@peteralbert](https://github.com/peteralbert)! - Remove the unused `glob` direct dependency. It was declared in `dependencies` but never imported anywhere in the source, and it resolved to the now-deprecated `glob@11.1.0`, which printed a deprecation warning on `npm i -g @skaile/workspaces`. Dropping it removes the warning and shrinks the install footprint.
17
+
18
+ ## 0.11.2
19
+
20
+ ### Patch Changes
21
+
22
+ - 4d91d69: fix(bridge): self-heal expired Claude OAuth credentials that surface as "Not logged in"
23
+
24
+ The claude-sdk driver's credential self-heal (`onAuthError`) failed to fire in two
25
+ cases, leaving sessions stuck on a misleading `Not logged in · Please run /login`
26
+ error after the OAuth access token expired:
27
+
28
+ - **Classification**: the bare `Not logged in · Please run /login` string the
29
+ Claude Code CLI emits (no JSON body) fell through to `category: "unknown"`, so it
30
+ was never promoted to `AuthError` and the self-heal never triggered. It is now
31
+ classified as `auth`.
32
+ - **Retry budget**: a stale-resume retry ("No conversation found with session ID")
33
+ consumed the single shared retry slot, so a subsequent auth failure on the
34
+ fresh-session retry could not reach the self-heal branch. Each recovery path
35
+ (stale-resume, poisoned-transcript, auth) now owns an independent one-shot budget.
36
+
37
+ Together these let the runner re-mint the credential and continue the turn instead
38
+ of dead-ending. Surfaced by a prod cloud session (2026-05-21).
39
+
3
40
  ## 0.11.1
4
41
 
5
42
  ### Patch Changes
@@ -125,6 +162,7 @@ authenticate. API Error: 401` even on every successful self-heal.
125
162
  `scrubPoisonedTranscript()` to repair the on-disk SDK JSONL transcript, then
126
163
  retries the resume once, keeping the same session so conversation context is
127
164
  preserved. Four poison classes are repaired in a single pass:
165
+
128
166
  - **Image `media_type` mismatch** — corrected by sniffing the base64 magic
129
167
  bytes (Claude Code `Read`-tool bug, anthropics/claude-code#55338 / #30124).
130
168
  - **Missing image `media_type`** — filled in from the sniffed bytes (#33179).
@@ -1,4 +1,4 @@
1
- export { resumeFlow, runFlow } from '../../../chunk-XYEFV7XN.js';
1
+ export { resumeFlow, runFlow } from '../../../chunk-DDVKNST3.js';
2
2
  import '../../../chunk-GCJXPUHG.js';
3
3
  import '../../../chunk-IPUYL6TD.js';
4
4
  import '../../../chunk-EAJKY27M.js';
@@ -1,7 +1,7 @@
1
- import { classifyClaudeSdkError, AuthError } from '../../chunk-EWP5HZBV.js';
1
+ import { AuthError, classifyClaudeSdkError } from '../../chunk-DQWREFRQ.js';
2
2
  import { fetchProviderModels } from '../../chunk-KOVLSBXK.js';
3
3
  import { dispatchCapability } from '../../chunk-RRVQAE5D.js';
4
- import { registerDriver, DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-YOFKTALB.js';
4
+ import { registerDriver, DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-4ACWI5YT.js';
5
5
  import '../../chunk-24UIWON4.js';
6
6
  import '../../chunk-NSBPE2FW.js';
7
7
  import { spawnSync } from 'child_process';
@@ -215,6 +215,9 @@ if (typeof globalThis.require === "undefined") {
215
215
  } catch {
216
216
  }
217
217
  }
218
+ function freshRetryBudget() {
219
+ return { staleResume: false, poison: false, auth: false };
220
+ }
218
221
  var ClaudeSdkDriver = class extends AgentDriver {
219
222
  driverInfo = {
220
223
  id: "claude-sdk",
@@ -238,16 +241,15 @@ var ClaudeSdkDriver = class extends AgentDriver {
238
241
  /** Guards against duplicate agent_end emissions per turn. */
239
242
  turnCompleted = false;
240
243
  /**
241
- * Mirror of the `_retryCount` argument of the in-flight {@link prompt} call.
242
- * Read by {@link failTurn} to decide whether to defer the `agent-event:
243
- * error` emission for a self-healable auth error. `0` means "first
244
- * attempt"; `prompt()` increments to `1` before recursing on its
245
- * `onAuthError` self-heal branch.
244
+ * Mirror of the in-flight {@link prompt} call's auth retry budget: `false`
245
+ * while the `onAuthError` self-heal is still available, `true` once it has
246
+ * been spent. Read by {@link failTurn} to decide whether to defer the
247
+ * `agent-event: error` emission for a self-healable auth error.
246
248
  *
247
249
  * Set unconditionally at the top of every {@link prompt} invocation; never
248
250
  * reset elsewhere — the next call's set is the only legitimate transition.
249
251
  */
250
- currentRetryCount = 0;
252
+ authSelfHealUsed = false;
251
253
  /** Tracks whether a session has been started (for continue: true). */
252
254
  hasSession = false;
253
255
  /** Session ID from the SDK — used for streamInput messages. */
@@ -323,11 +325,12 @@ var ClaudeSdkDriver = class extends AgentDriver {
323
325
  * "No conversation found with session ID …" — a recoverable stale-resume error that
324
326
  * occurs after a container crash that prevented the SDK from flushing its session file.
325
327
  */
326
- async prompt(message, _retryCount = 0) {
327
- this.currentRetryCount = _retryCount;
328
+ async prompt(message, _budget = freshRetryBudget()) {
329
+ this.authSelfHealUsed = _budget.auth;
328
330
  if (!this.sdk) await this.start();
329
331
  let retrying = false;
330
- if (_retryCount === 0) this._lastTokens = null;
332
+ const isFirstAttempt = !_budget.staleResume && !_budget.poison && !_budget.auth;
333
+ if (isFirstAttempt) this._lastTokens = null;
331
334
  this.running = true;
332
335
  this.prevText = "";
333
336
  this.turnCompleted = false;
@@ -352,7 +355,7 @@ var ClaudeSdkDriver = class extends AgentDriver {
352
355
  await turnPromise;
353
356
  } catch (err) {
354
357
  const errMsg = err instanceof Error ? err.message : String(err);
355
- const isStaleResume = _retryCount === 0 && /No conversation found with session ID/i.test(errMsg);
358
+ const isStaleResume = !_budget.staleResume && /No conversation found with session ID/i.test(errMsg);
356
359
  if (isStaleResume) {
357
360
  const staleId = this.config.resumeSessionId || this.sessionId || "unknown";
358
361
  this.log.warn("stale Claude Code session, retrying with a fresh session", { staleId });
@@ -374,9 +377,9 @@ var ClaudeSdkDriver = class extends AgentDriver {
374
377
  this.turnReject = null;
375
378
  this.running = false;
376
379
  retrying = true;
377
- return this.prompt(message, _retryCount + 1);
380
+ return this.prompt(message, { ..._budget, staleResume: true });
378
381
  }
379
- const isPoisonedHistory = _retryCount === 0 && /invalid_request_error/i.test(errMsg) && /media[_ ]?type|could not process image|image exceeds|cache_control/i.test(errMsg);
382
+ const isPoisonedHistory = !_budget.poison && /invalid_request_error/i.test(errMsg) && /media[_ ]?type|could not process image|image exceeds|cache_control/i.test(errMsg);
380
383
  const poisonSessionId = this.config.resumeSessionId || this.sessionId;
381
384
  if (isPoisonedHistory && poisonSessionId) {
382
385
  const scrub = scrubPoisonedTranscript({
@@ -416,14 +419,14 @@ var ClaudeSdkDriver = class extends AgentDriver {
416
419
  this.turnReject = null;
417
420
  this.running = false;
418
421
  retrying = true;
419
- return this.prompt(message, _retryCount + 1);
422
+ return this.prompt(message, { ..._budget, poison: true });
420
423
  }
421
424
  this.log.warn("poisoned-transcript error but scrub found nothing to repair", {
422
425
  sessionId: poisonSessionId,
423
426
  filePath: scrub.filePath
424
427
  });
425
428
  }
426
- const isAuthError = err instanceof AuthError && _retryCount === 0;
429
+ const isAuthError = err instanceof AuthError && !_budget.auth;
427
430
  if (isAuthError && this.config.onAuthError) {
428
431
  this.log.info("auth error caught; invoking onAuthError refresh callback");
429
432
  let refreshed = false;
@@ -449,7 +452,7 @@ var ClaudeSdkDriver = class extends AgentDriver {
449
452
  this.turnReject = null;
450
453
  this.running = false;
451
454
  retrying = true;
452
- return this.prompt(message, _retryCount + 1);
455
+ return this.prompt(message, { ..._budget, auth: true });
453
456
  }
454
457
  try {
455
458
  this.emit("agent-event", {
@@ -785,16 +788,16 @@ var ClaudeSdkDriver = class extends AgentDriver {
785
788
  * caller transitions even if the listener chain misbehaves; the emit is
786
789
  * wrapped in try/catch so a listener failure cannot leak out.
787
790
  *
788
- * Self-heal deferral: when the failure is an {@link AuthError} on the
789
- * first attempt (`currentRetryCount === 0`) AND the caller wired an
790
- * `onAuthError` callback, the downstream `agent-event: error` emission
791
- * is deferred. The rejected turn promise still travels to {@link prompt}'s
792
- * catch block where the self-heal runs; if the retry succeeds the user
793
- * never sees a 401, if the retry fails the second `failTurn` call (now
794
- * with `currentRetryCount === 1`) emits the error normally. This stops
795
- * the historical "401 flashes in the UI even though self-heal worked"
796
- * misbehaviour where the bridge emitted the error event before the
797
- * retry decision was known.
791
+ * Self-heal deferral: when the failure is an {@link AuthError} and the auth
792
+ * self-heal budget is still available (`!authSelfHealUsed`) AND the caller
793
+ * wired an `onAuthError` callback, the downstream `agent-event: error`
794
+ * emission is deferred. The rejected turn promise still travels to
795
+ * {@link prompt}'s catch block where the self-heal runs; if the retry
796
+ * succeeds the user never sees a 401, if the retry fails the second
797
+ * `failTurn` call (now with `authSelfHealUsed === true`) emits the error
798
+ * normally. This stops the historical "401 flashes in the UI even though
799
+ * self-heal worked" misbehaviour where the bridge emitted the error event
800
+ * before the retry decision was known.
798
801
  *
799
802
  * Spec: `_devlog/specs/2026-05-07-unified-credential-mediation.md`
800
803
  * § "Runner-side handling on 401" (the AI 401 mediation path that
@@ -807,7 +810,7 @@ var ClaudeSdkDriver = class extends AgentDriver {
807
810
  this.turnReject = null;
808
811
  }
809
812
  this.turnCompleted = true;
810
- const willSelfHeal = err instanceof AuthError && this.currentRetryCount === 0 && this.config.onAuthError != null;
813
+ const willSelfHeal = err instanceof AuthError && !this.authSelfHealUsed && this.config.onAuthError != null;
811
814
  if (willSelfHeal) {
812
815
  this.log.info("deferring auth-error event; self-heal will attempt refresh");
813
816
  return;