@huynle/hub 0.9.2 → 0.10.1

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 (141) hide show
  1. package/CHANGELOG.md +320 -0
  2. package/Dockerfile +5 -1
  3. package/README.md +154 -77
  4. package/package.json +7 -4
  5. package/packages/claude-code/package.json +1 -1
  6. package/packages/cli/dist/hub-cli.js +534 -261
  7. package/packages/cli/package.json +1 -1
  8. package/packages/cli/src/cli.ts +36 -1
  9. package/packages/cli/src/subscriptions.ts +49 -0
  10. package/packages/codex/package.json +1 -1
  11. package/packages/codex/src/sessions.ts +10 -6
  12. package/packages/codex/src/spoke.ts +2 -1
  13. package/packages/node/package.json +1 -1
  14. package/packages/preset/package.json +1 -1
  15. package/packages/protocol/package.json +1 -1
  16. package/packages/protocol/schema/app-delivery/v1.schema.json +7 -5
  17. package/packages/protocol/schema/app-front/v1.schema.json +410 -0
  18. package/packages/protocol/src/app-front.ts +293 -0
  19. package/packages/protocol/src/concierge.ts +10 -1
  20. package/packages/protocol/src/context-cards.ts +59 -0
  21. package/packages/protocol/src/credentials.ts +39 -2
  22. package/packages/protocol/src/index.ts +81 -11
  23. package/packages/runtime-openshell/package.json +1 -1
  24. package/packages/runtime-sdk/package.json +1 -1
  25. package/packages/sdk/package.json +1 -1
  26. package/packages/sdk/src/app-front.ts +524 -0
  27. package/packages/sdk/src/client.ts +37 -4
  28. package/packages/sdk/src/envelope.ts +9 -2
  29. package/packages/sdk/src/errors.ts +1 -0
  30. package/packages/sdk/src/index.ts +1 -0
  31. package/packages/sdk/src/types.ts +39 -1
  32. package/packages/spoke-sdk/package.json +1 -1
  33. package/packages/spoke-sdk/src/delivery.ts +17 -1
  34. package/packages/spoke-sdk/src/harness-spoke.ts +4 -3
  35. package/packages/voice-client/README.md +146 -0
  36. package/packages/voice-client/src/vad/LICENSE +21 -0
  37. package/src/central/agent/acting-routes.ts +17 -3
  38. package/src/central/agent/acting.ts +12 -3
  39. package/src/central/agent/actor.ts +6 -1
  40. package/src/central/agent/app-decisions.ts +146 -0
  41. package/src/central/agent/app-tokens.ts +9 -3
  42. package/src/central/agent/audit.ts +3 -0
  43. package/src/central/agent/connect-routes.ts +64 -0
  44. package/src/central/agent/connect.ts +868 -0
  45. package/src/central/agent/conversation.ts +625 -0
  46. package/src/central/agent/decisions.ts +71 -6
  47. package/src/central/agent/delivery.ts +3 -0
  48. package/src/central/agent/directory.ts +5 -0
  49. package/src/central/agent/errors.ts +2 -0
  50. package/src/central/agent/grant-requests.ts +46 -9
  51. package/src/central/agent/grants.ts +13 -2
  52. package/src/central/agent/message-limits.ts +2 -2
  53. package/src/central/agent/message-routes.ts +13 -4
  54. package/src/central/agent/read-routes.ts +16 -2
  55. package/src/central/agent/routes.ts +108 -6
  56. package/src/central/agent/speech-routes.ts +316 -0
  57. package/src/central/agent/subscription-routes.ts +174 -0
  58. package/src/central/agent/subscriptions.ts +980 -0
  59. package/src/central/agent-data.ts +43 -1
  60. package/src/central/backend/memory-counters.ts +2 -2
  61. package/src/central/backend/types.ts +5 -2
  62. package/src/central/backend/valkey-counters.ts +5 -4
  63. package/src/central/client-address.ts +16 -0
  64. package/src/central/concierge/board-render.ts +52 -1
  65. package/src/central/concierge/board-routes.ts +25 -2
  66. package/src/central/concierge/board.ts +11 -1
  67. package/src/central/concierge/context.ts +29 -8
  68. package/src/central/concierge/grant-request.ts +216 -0
  69. package/src/central/concierge/prompt.ts +49 -2
  70. package/src/central/concierge/session-routes.ts +3 -0
  71. package/src/central/config.ts +64 -3
  72. package/src/central/context-cards/budget.ts +121 -0
  73. package/src/central/context-cards/changes.ts +29 -0
  74. package/src/central/context-cards/config.ts +145 -0
  75. package/src/central/context-cards/engine.ts +379 -0
  76. package/src/central/context-cards/inputs.ts +111 -0
  77. package/src/central/context-cards/pickup.ts +134 -0
  78. package/src/central/context-cards/registry.ts +89 -0
  79. package/src/central/context-cards/routes.ts +37 -0
  80. package/src/central/context-cards/service.ts +367 -0
  81. package/src/central/context-cards/store.ts +67 -0
  82. package/src/central/context-cards/types.ts +88 -0
  83. package/src/central/fetcher.ts +10 -2
  84. package/src/central/front-relays.ts +423 -0
  85. package/src/central/http.ts +547 -58
  86. package/src/central/human-activity.ts +453 -0
  87. package/src/central/llm/chat.ts +133 -0
  88. package/src/central/registry.ts +162 -9
  89. package/src/central/speech/service.ts +9 -0
  90. package/src/central/spoke-ws.ts +13 -0
  91. package/src/central/store.ts +9 -12
  92. package/src/config.ts +30 -13
  93. package/src/index.ts +45 -43
  94. package/src/rpc.ts +33 -4
  95. package/src/spoke/concierge-agent.ts +1 -1
  96. package/src/spoke/conversation.ts +6 -75
  97. package/src/spoke/deliver.ts +18 -8
  98. package/src/spoke/hub-rpc.ts +7 -2
  99. package/src/spoke/hub-tool-subscriptions.ts +82 -0
  100. package/src/spoke/hub-tool-title.ts +89 -0
  101. package/src/spoke/hub-tool.ts +56 -18
  102. package/src/spoke/session-context.ts +10 -2
  103. package/src/spoke/spoke.ts +227 -237
  104. package/src/spoke/summary.ts +36 -1
  105. package/src/spoke/taskboard.ts +5 -6
  106. package/src/spoke/voice-front.ts +323 -30
  107. package/src/spoke/who-teams.ts +51 -2
  108. package/src/tui-messaging.ts +24 -10
  109. package/src/tui.ts +6 -6
  110. package/web/dist/assets/{ArtifactPage-BKISN-Qj.js → ArtifactPage-CsPjam8D.js} +1 -1
  111. package/web/dist/assets/{ArtifactPane-CKOiAUNH.js → ArtifactPane-B9weO8L6.js} +1 -1
  112. package/web/dist/assets/ArtifactWorkbench-DzKhMs3l.js +6 -0
  113. package/web/dist/assets/{Diagram-vdpmp3xu.css → Diagram-7y8kg3og.css} +1 -1
  114. package/web/dist/assets/Diagram-CuRIffka.js +1 -0
  115. package/web/dist/assets/{Library-CcjZXsfF.js → Library-rv5DGtrm.js} +2 -2
  116. package/web/dist/assets/Lightbox-BlbivCkd.js +1 -0
  117. package/web/dist/assets/MediaImage-Ch3ryIdR.js +4 -0
  118. package/web/dist/assets/ProfilesDestination-DUuQ9jmd.js +1 -0
  119. package/web/dist/assets/{TeamsPage-CDyjrK-I.js → TeamsPage-D_17MkvN.js} +1 -1
  120. package/web/dist/assets/{Watchtower-DYwoUWME.js → Watchtower-DlrNOJ7X.js} +2 -2
  121. package/web/dist/assets/{artifacts-DU9uRgs1.js → artifacts-But87Jfo.js} +1 -1
  122. package/web/dist/assets/index-bX8B6NLo.js +33 -0
  123. package/web/dist/assets/index-rW6LKQj1.css +1 -0
  124. package/web/dist/assets/{live-ycZ_aQZO.js → live-BGLA-peO.js} +2 -2
  125. package/web/dist/assets/{pane-layout-0RrLHGDr.js → pane-layout-BW0RdX5a.js} +1 -1
  126. package/web/dist/assets/{renderer2d-BIwbgRoX.js → renderer2d-DyANQ1WS.js} +1 -1
  127. package/web/dist/assets/{renderer3d-C1a7eYGQ.js → renderer3d-vYYKFAJq.js} +1 -1
  128. package/web/dist/assets/{safe-area-DHhPy61Q.js → safe-area-B2Bk__FK.js} +1 -1
  129. package/web/dist/assets/{source-BWlvaODa.js → source-C-De8L3s.js} +1 -1
  130. package/web/dist/assets/toast-CXTwTvDw.js +9 -0
  131. package/web/dist/assets/vad-worklet-BfxJhrXy.js +27 -0
  132. package/web/dist/index.html +6 -6
  133. package/web/dist/assets/ArtifactWorkbench-d7R1o-rs.js +0 -6
  134. package/web/dist/assets/Diagram-azw2B_QH.js +0 -1
  135. package/web/dist/assets/Lightbox-Du56MXGX.js +0 -1
  136. package/web/dist/assets/MediaImage-Ds_JUx3a.js +0 -4
  137. package/web/dist/assets/ProfilesDestination-DdzbzmeK.js +0 -1
  138. package/web/dist/assets/index-C3ci5UtY.css +0 -1
  139. package/web/dist/assets/index-LNMZCqgE.js +0 -36
  140. package/web/dist/assets/toast-Cuu2K0hx.js +0 -1
  141. /package/{web/src/voice → packages/voice-client/src}/turn/LICENSE +0 -0
@@ -34,6 +34,7 @@ export * from "./hub-workspace.ts"
34
34
  export * from "./concierge.ts"
35
35
  export * from "./profiles.ts"
36
36
  export * from "./artifacts.ts"
37
+ export * from "./context-cards.ts"
37
38
  export * from "./embedded-media.ts"
38
39
  export * from "./media.ts"
39
40
  export * from "./media-allowlist.ts"
@@ -41,6 +42,7 @@ export * from "./preview-bundle.ts"
41
42
  export * from "./teams.ts"
42
43
  export * from "./graph.ts"
43
44
  export * from "./voice-recording.ts"
45
+ export * from "./app-front.ts"
44
46
  export { HUB_URL_MAX_CHARS, isHubURL, MAX_FRAME, MAX_RETRY_AFTER_MS }
45
47
 
46
48
  export const PROTOCOL_VERSION = 1
@@ -84,7 +86,9 @@ export interface ModelSelection {
84
86
  }
85
87
 
86
88
  export interface SessionModelPrefs {
89
+ /** The voice front's model for this session. */
87
90
  readonly voice?: ModelSelection
91
+ /** Obsolete (the removed voice agent's worker model): older hubs and spokes still send it; it is ignored. */
88
92
  readonly worker?: ModelSelection
89
93
  }
90
94
 
@@ -323,11 +327,16 @@ export const FORWARDED_EVENTS: ReadonlySet<string> = new Set([
323
327
  export const INBOX_ORIGINS = ["user", "hub"] as const
324
328
  export type InboxOrigin = (typeof INBOX_ORIGINS)[number]
325
329
 
326
- /** `session.inbox.delivered` data as forwarded. `origin` is optional: older spokes do not send it. */
330
+ /**
331
+ * `session.inbox.delivered` data as forwarded. `origin` is optional: older spokes do not send it. `carried` (feature
332
+ * "inboxCarried"): a user item the hub carried itself (a console turn or steer, a Voice utterance, a launch's prompt),
333
+ * never a prompt typed in the terminal.
334
+ */
327
335
  export interface InboxDeliveredData {
328
336
  readonly sessionID: string
329
337
  readonly inboxID: string
330
338
  readonly origin?: InboxOrigin
339
+ readonly carried?: true
331
340
  }
332
341
 
333
342
  /**
@@ -466,8 +475,15 @@ export const IMPLIED_OPENCODE_FEATURES = [
466
475
  * carry media refs (user files' `ref`, tool and assistant rows' `media`).
467
476
  * "previewBundle": it answers previewBundle (preview-bundle.ts): a local HTML page an assistant message names and the
468
477
  * files it refers to, under the media path policy, paged under the frame limit.
478
+ * "conciergeFront" (voice front P2): it puts a voice front in front of a locked (Concierge) session when the hub asks
479
+ * with `front`, serves frontUpdate, and takes the session-context part "frontBoard" (the front's compact board).
480
+ * "inboxCarried": its session.inbox.delivered marks a user item the hub carried (`carried: true`), so every other
481
+ * user item is a prompt typed in the terminal. Spokes of harnesses that report the hub's prompts as origin "hub"
482
+ * need not announce it.
483
+ * "setModel": it sets the session's own model (setModel op) the way the harness keeps it for every later turn of
484
+ * that session (OpenCode: session.switchModel, stored on the session), whoever prompts it next.
469
485
  */
470
- const OPTIONAL_SPOKE_FEATURES = [...IMPLIED_OPENCODE_FEATURES, "autoName", "sessionTokens", "deliver", "hubPrompt", "permissionMessage", "actTokens", "launch", "fork", "revert", "dismissError", "timelineMedia", PREVIEW_BUNDLE_FEATURE, "voiceFront"] as const
486
+ const OPTIONAL_SPOKE_FEATURES = [...IMPLIED_OPENCODE_FEATURES, "autoName", "sessionTokens", "deliver", "hubPrompt", "permissionMessage", "actTokens", "launch", "fork", "revert", "dismissError", "timelineMedia", PREVIEW_BUNDLE_FEATURE, "voiceFront", "conciergeFront", "inboxCarried", "setModel"] as const
471
487
 
472
488
  /**
473
489
  * The core ops. An OpenCode spoke serves them all without announcing them; a spoke of another harness announces
@@ -503,11 +519,12 @@ export const SPOKE_FEATURES: readonly SpokeFeature[] = [...OPTIONAL_SPOKE_FEATUR
503
519
  * "pendingReplay": the hub takes a re-announced permission.asked / form.created (after a spoke reconnects) without
504
520
  * notifying again, and honours `unlisted: true` on form.cancelled / permission.replied (only that process stops
505
521
  * holding it). Spokes re-send permissions the hub was told already only to a hub that announces it.
522
+ * "frontRelay" (voice front P2): it serves the spoke request relayToSession (a Concierge front's relay_to_session).
506
523
  */
507
- export const KNOWN_HUB_FEATURES = ["harness", "messaging", "nodes", "launches", "pendingReplay"] as const
524
+ export const KNOWN_HUB_FEATURES = ["harness", "messaging", "nodes", "launches", "pendingReplay", "frontRelay"] as const
508
525
  export type HubFeature = (typeof KNOWN_HUB_FEATURES)[number]
509
526
  /** What this hub announces ("launches": the /api/agent/launches routes). */
510
- export const HUB_FEATURES: readonly HubFeature[] = ["harness", "messaging", "nodes", "launches", "pendingReplay"]
527
+ export const HUB_FEATURES: readonly HubFeature[] = ["harness", "messaging", "nodes", "launches", "pendingReplay", "frontRelay"]
511
528
 
512
529
  /** A spoke's harness, version and evidence level; a hello without `harness` is an OpenCode native spoke. */
513
530
  export function helloHarness(hello: Hello): { readonly harness: string; readonly harnessVersion: string; readonly evidence: EvidenceLevel | "unknown" } {
@@ -548,6 +565,21 @@ export type SpokeRequest =
548
565
  /** A one-time sign-in link to a session's page, or to the home page without a session. */
549
566
  /** `voice`: land on the session with Voice mode starting (`?voice=1`). */
550
567
  | { readonly op: "openLink"; readonly sessionID?: string; readonly voice?: boolean }
568
+ /**
569
+ * (hub feature "frontRelay", voice front P2) A Concierge front's relay_to_session: the user's spoken request, as a
570
+ * message to `session` (@name or session ID), one of the user's own sessions. The hub checks the front, the
571
+ * utterance it answers and the target; a refusal is ok:false with the reason the front reads. The hub delivers the
572
+ * user's own words (its record of the utterance), never `text`: `text` is the front's short note, sent along only
573
+ * when every content word in it is one the user said. `previous` (a redirect, "no, the other one"): the user's
574
+ * utterance before this one goes first. `confirm` (guard tuning): one retry after the hub's soft refusal of a question
575
+ * with a work verb, for the same utterance and session.
576
+ */
577
+ | { readonly op: "relayToSession"; readonly frontID: string; readonly session: string; readonly text: string; readonly previous?: boolean; readonly confirm?: boolean }
578
+
579
+ /** The longest relay text (as an utterance). */
580
+ export const RELAY_TEXT_MAX = 4000
581
+ /** The longest front update text. */
582
+ export const FRONT_UPDATE_MAX = 8000
551
583
 
552
584
  // ---------- server → spoke ----------
553
585
 
@@ -659,18 +691,23 @@ export type ServerRequest =
659
691
  /** One changed file's patch in the session's directory. */
660
692
  | { readonly op: "diff"; readonly sessionID: string; readonly file: string }
661
693
  /**
662
- * Switch the session to the voice orchestrator agent (on) or back to its previous agent (off). `front` (feature
663
- * "voiceFront", sent only to spokes that list it): leave the session's agent and model untouched and put a hidden
664
- * voice-front session in front of it instead (docs/plans/2026-11-06-voice-front-p1-contract.md).
665
- */
666
- /**
667
- * `front` (feature "voiceFront"): put a hidden voice front in front of the session. `frontID`: the front the hub
668
- * knows for it (a resend to a restarted spoke): re-linked if it still exists, instead of creating another.
694
+ * Conversation (Voice) mode on or off. The session's agent and model are never switched (older spokes switched it
695
+ * to a "voice" agent). `front` (feature "voiceFront", sent only to spokes that list it): put a hidden voice front in
696
+ * front of the session (docs/plans/2026-11-06-voice-front-p1-contract.md); without it, or when no front can be made,
697
+ * the hub talks to the session itself and its turns are voice-styled. `frontID`: the front the hub knows for it (a
698
+ * resend to a restarted spoke): re-linked if it still exists, instead of creating another.
669
699
  */
670
700
  | { readonly op: "conversation"; readonly sessionID: string; readonly on: boolean; readonly front?: boolean; readonly frontID?: string }
671
701
  | { readonly op: "models"; readonly sessionID: string }
672
702
  | { readonly op: "modelPrefs"; readonly sessionID: string }
703
+ /** `worker` is obsolete: older hubs send it, current spokes ignore it. */
673
704
  | { readonly op: "setModelPrefs"; readonly sessionID: string; readonly voice?: ModelSelection | null; readonly worker?: ModelSelection | null }
705
+ /**
706
+ * (feature "setModel") Set the session's own model: every later turn of the session runs on it, whoever prompts it
707
+ * (the console, the terminal, a voice relay). One of the session's catalog models (models op); no variant: the
708
+ * model's default. The Voice model (setModelPrefs) is separate and never changes it.
709
+ */
710
+ | { readonly op: "setModel"; readonly sessionID: string; readonly model: ModelSelection }
674
711
  | { readonly op: "timeline"; readonly sessionID: string; readonly limit?: number; readonly cursor?: string; readonly order?: "asc" | "desc"; readonly before?: string }
675
712
  | { readonly op: "timelinePart"; readonly sessionID: string; readonly messageID: string; readonly partID: string }
676
713
  /** One image attached to a user message (its position in the message's files). */
@@ -750,6 +787,11 @@ export type ServerRequest =
750
787
  | { readonly op: "removeFront"; readonly sessionID: string }
751
788
  /** Forget the session's last run failure: the user dismissed it (feature "dismissError"). */
752
789
  | { readonly op: "dismissError"; readonly sessionID: string }
790
+ /**
791
+ * (feature "conciergeFront", voice front P2) An update for the voice front of `sessionID` (the Concierge session)
792
+ * about a session it relayed to: queued as its next wake. `finished`: a successful turn end.
793
+ */
794
+ | { readonly op: "frontUpdate"; readonly sessionID: string; readonly text: string; readonly finished?: boolean }
753
795
 
754
796
  /**
755
797
  * The feature a spoke must serve (spokeFeatures) for the hub to send `op`: the op itself for a core op (CORE_OPS,
@@ -765,6 +807,8 @@ export function featureForOp(op: ServerRequest["op"]): SpokeFeature {
765
807
  return "revert"
766
808
  case "removeFront":
767
809
  return "voiceFront"
810
+ case "frontUpdate":
811
+ return "conciergeFront"
768
812
  default:
769
813
  return op
770
814
  }
@@ -831,10 +875,23 @@ export interface FilePatch extends ChangedFile {
831
875
  }
832
876
 
833
877
  /** Right-rail data for a session; each part is absent when OpenCode could not provide it. */
878
+ /**
879
+ * The model a session runs on, as its spoke knows it (the console's model chip). Voice never changes it: the voice
880
+ * front is a separate session. `name` from the model catalog; `variant` only when explicit. `source`: `chosen`, the
881
+ * model selected for the session; `reply`, nothing selected, the model its latest reply ran on (the default resolved);
882
+ * `default`, nothing selected and no reply yet, the default model.
883
+ */
884
+ export interface SessionModel extends ModelSelection {
885
+ readonly name?: string
886
+ readonly source: "chosen" | "reply" | "default"
887
+ }
888
+
834
889
  export interface SessionSummary {
835
890
  readonly directory: string
836
891
  readonly branch?: string
837
892
  readonly context?: ContextUsage
893
+ /** The model the session runs on (absent when nothing is known, or from older spokes). */
894
+ readonly model?: SessionModel
838
895
  readonly mcp?: readonly McpStatus[]
839
896
  readonly changes?: SessionChanges
840
897
  }
@@ -871,6 +928,8 @@ export interface ResultFor {
871
928
  models: { readonly models: readonly AvailableModel[] }
872
929
  modelPrefs: { readonly prefs: SessionModelPrefs; readonly defaults: SessionModelPrefs }
873
930
  setModelPrefs: { readonly prefs: SessionModelPrefs; readonly defaults: SessionModelPrefs }
931
+ /** `model`: the session's model now (source "chosen"). */
932
+ setModel: { readonly model: SessionModel }
874
933
  timeline: TimelinePage
875
934
  timelinePart: { readonly detail: unknown }
876
935
  /** No `file` when the message has no image at that index; `tooLarge` when its bytes would not fit in a frame. */
@@ -896,6 +955,10 @@ export interface ResultFor {
896
955
  /** `dismissed`: the spoke had a failure of the session to forget. */
897
956
  dismissError: { readonly dismissed: boolean }
898
957
  removeFront: { readonly removed: boolean }
958
+ /** `queued`: false when the session has no linked front in this process. */
959
+ frontUpdate: { readonly queued: boolean }
960
+ /** The session the relay reached, its title, and how: steered into its running turn, or a new turn. */
961
+ relayToSession: { readonly sessionID: string; readonly title?: string; readonly mode: "steer" | "turn" }
899
962
  }
900
963
 
901
964
  // ---------- both directions ----------
@@ -1120,6 +1183,9 @@ function isSpokeRequest(v: unknown): v is SpokeRequest {
1120
1183
  if (v.op === "pairCode") return true
1121
1184
  if (v.op === "handoff") return nonEmpty(v.sessionID)
1122
1185
  if (v.op === "openLink") return (v.sessionID === undefined || nonEmpty(v.sessionID)) && (v.voice === undefined || typeof v.voice === "boolean")
1186
+ if (v.op === "relayToSession") {
1187
+ return nonEmpty(v.frontID) && v.frontID.length <= 300 && nonEmpty(v.session) && v.session.length <= 300 && str(v.text) && v.text.trim().length > 0 && v.text.length <= RELAY_TEXT_MAX && (v.previous === undefined || typeof v.previous === "boolean") && (v.confirm === undefined || typeof v.confirm === "boolean")
1188
+ }
1123
1189
  return false
1124
1190
  }
1125
1191
 
@@ -1212,6 +1278,8 @@ function isServerRequest(v: unknown): v is ServerRequest {
1212
1278
  (v.worker === undefined || v.worker === null || isModelSelection(v.worker)) &&
1213
1279
  (v.voice !== undefined || v.worker !== undefined)
1214
1280
  )
1281
+ case "setModel":
1282
+ return nonEmpty(v.sessionID) && isModelSelection(v.model)
1215
1283
  case "timeline":
1216
1284
  return (
1217
1285
  nonEmpty(v.sessionID) &&
@@ -1272,6 +1340,8 @@ function isServerRequest(v: unknown): v is ServerRequest {
1272
1340
  case "dismissError":
1273
1341
  case "removeFront":
1274
1342
  return nonEmpty(v.sessionID)
1343
+ case "frontUpdate":
1344
+ return nonEmpty(v.sessionID) && str(v.text) && v.text.trim().length > 0 && v.text.length <= FRONT_UPDATE_MAX && (v.finished === undefined || typeof v.finished === "boolean")
1275
1345
  default:
1276
1346
  return false
1277
1347
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huynle/hub-runtime-openshell",
3
- "version": "0.9.2",
3
+ "version": "0.10.1",
4
4
  "private": true,
5
5
  "description": "The `openshell` runtime of `hub node`: launches in NVIDIA OpenShell sandboxes, driven through the openshell CLI (internal; shipped inside @huynle/hub, not published on its own).",
6
6
  "license": "MIT",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huynle/hub-runtime-sdk",
3
- "version": "0.9.2",
3
+ "version": "0.10.1",
4
4
  "private": true,
5
5
  "description": "The Runtime interface `hub node` runtimes implement (internal; shipped inside @huynle/hub, not published on its own).",
6
6
  "license": "MIT",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@huynle/hub-sdk",
3
- "version": "0.9.2",
3
+ "version": "0.10.1",
4
4
  "private": true,
5
5
  "description": "Typed client for the hub's /api/agent (internal; shipped inside @huynle/hub, not published on its own).",
6
6
  "license": "MIT",