@blade-hq/agent-kit 1.0.0 → 1.0.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.
Files changed (35) hide show
  1. package/dist/{SkillStatusBar-Dp93pqlP.d.ts → SkillStatusBar-dAc3k2rZ.d.ts} +2 -2
  2. package/dist/{blade-client-DS7lV19a.d.ts → blade-client-BDKe7LRv.d.ts} +25 -3
  3. package/dist/{chunk-LVWRKH45.js → chunk-6PKGWPIK.js} +2 -2
  4. package/dist/{chunk-DQXXSHCR.js → chunk-DN4CKDDQ.js} +46 -5
  5. package/dist/chunk-DN4CKDDQ.js.map +1 -0
  6. package/dist/{chunk-OVOZQHYQ.js → chunk-HRQSJO3P.js} +45 -6
  7. package/dist/chunk-HRQSJO3P.js.map +1 -0
  8. package/dist/{chunk-IRHXGYY3.js → chunk-O5FJLN6G.js} +3 -3
  9. package/dist/{chunk-KSYNFNF4.js → chunk-QMYGPQCX.js} +2 -2
  10. package/dist/{chunk-II2PTBJI.js → chunk-U7Y7GRF6.js} +145 -17
  11. package/dist/chunk-U7Y7GRF6.js.map +1 -0
  12. package/dist/client/index.d.ts +1422 -149
  13. package/dist/client/index.js +1 -1
  14. package/dist/react/api/vibe-coding.d.ts +3 -3
  15. package/dist/react/api/vibe-coding.js +2 -2
  16. package/dist/react/components/chat/index.d.ts +4 -4
  17. package/dist/react/components/chat/index.js +5 -5
  18. package/dist/react/components/plan/index.js +4 -4
  19. package/dist/react/components/session/index.d.ts +1 -1
  20. package/dist/react/components/session/index.js +3 -3
  21. package/dist/react/components/workspace/index.d.ts +3 -3
  22. package/dist/react/components/workspace/index.js +140 -129
  23. package/dist/react/components/workspace/index.js.map +1 -1
  24. package/dist/react/index.d.ts +37 -10
  25. package/dist/react/index.js +49 -16
  26. package/dist/react/index.js.map +1 -1
  27. package/dist/{session-B5v5KkVd.d.ts → session-o8bAQoXK.d.ts} +11 -1
  28. package/dist/{sessions-DaddUdO6.d.ts → sessions-D_cIKSO6.d.ts} +2 -2
  29. package/package.json +1 -1
  30. package/dist/chunk-DQXXSHCR.js.map +0 -1
  31. package/dist/chunk-II2PTBJI.js.map +0 -1
  32. package/dist/chunk-OVOZQHYQ.js.map +0 -1
  33. /package/dist/{chunk-LVWRKH45.js.map → chunk-6PKGWPIK.js.map} +0 -0
  34. /package/dist/{chunk-IRHXGYY3.js.map → chunk-O5FJLN6G.js.map} +0 -0
  35. /package/dist/{chunk-KSYNFNF4.js.map → chunk-QMYGPQCX.js.map} +0 -0
@@ -5,12 +5,12 @@ import {
5
5
  import {
6
6
  getSessionFilePath,
7
7
  resolveSessionFilePreviewTarget
8
- } from "./chunk-LVWRKH45.js";
8
+ } from "./chunk-6PKGWPIK.js";
9
9
  import {
10
10
  formatToolName,
11
11
  getAuthedUrl,
12
12
  useUiStore
13
- } from "./chunk-II2PTBJI.js";
13
+ } from "./chunk-U7Y7GRF6.js";
14
14
  import {
15
15
  cn,
16
16
  copyToClipboard
@@ -1933,4 +1933,4 @@ export {
1933
1933
  PlanSummaryCard,
1934
1934
  extractLatestPlanMessages
1935
1935
  };
1936
- //# sourceMappingURL=chunk-IRHXGYY3.js.map
1936
+ //# sourceMappingURL=chunk-O5FJLN6G.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  useSessionStore
3
- } from "./chunk-II2PTBJI.js";
3
+ } from "./chunk-U7Y7GRF6.js";
4
4
 
5
5
  // src/react/hooks/use-session.ts
6
6
  function useSession() {
@@ -27,4 +27,4 @@ function useSession() {
27
27
  export {
28
28
  useSession
29
29
  };
30
- //# sourceMappingURL=chunk-KSYNFNF4.js.map
30
+ //# sourceMappingURL=chunk-QMYGPQCX.js.map
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-J3XVFPOV.js";
4
4
  import {
5
5
  BladeClient
6
- } from "./chunk-DQXXSHCR.js";
6
+ } from "./chunk-DN4CKDDQ.js";
7
7
  import {
8
8
  createClientActions,
9
9
  useCardStateStore
@@ -887,17 +887,37 @@ if (isBrowser) {
887
887
  });
888
888
  }
889
889
  function removeArtifactAtIndex(state, index) {
890
+ const removed = state.artifacts[index];
891
+ const removedKey = removed ? getPreviewTargetKey(removed) : null;
890
892
  const next = state.artifacts.filter((_, i) => i !== index);
891
893
  let nextActive = state.activeArtifactIndex;
892
894
  if (next.length === 0) {
893
- return { artifacts: [], activeArtifactIndex: -1, rightPanelCollapsed: true };
895
+ return {
896
+ artifacts: [],
897
+ activeArtifactIndex: -1,
898
+ previewUnreadArtifactKeys: [],
899
+ rightPanelUnreadTabs: state.rightPanelUnreadTabs.filter((tab) => tab !== "files"),
900
+ rightPanelCollapsed: true
901
+ };
894
902
  }
895
903
  if (index < nextActive) {
896
904
  nextActive -= 1;
897
905
  } else if (index === nextActive) {
898
906
  nextActive = Math.min(index, next.length - 1);
899
907
  }
900
- return { artifacts: next, activeArtifactIndex: nextActive };
908
+ const previewUnreadArtifactKeys = removedKey ? state.previewUnreadArtifactKeys.filter((key) => key !== removedKey) : state.previewUnreadArtifactKeys;
909
+ return {
910
+ artifacts: next,
911
+ activeArtifactIndex: nextActive,
912
+ previewUnreadArtifactKeys,
913
+ rightPanelUnreadTabs: previewUnreadArtifactKeys.length === 0 ? state.rightPanelUnreadTabs.filter((tab) => tab !== "files") : state.rightPanelUnreadTabs
914
+ };
915
+ }
916
+ function getPreviewTargetKey(target) {
917
+ return target.key ?? target.title ?? target.type;
918
+ }
919
+ function addUnique(values, value) {
920
+ return values.includes(value) ? values : [...values, value];
901
921
  }
902
922
  function upsertArtifactState(state, target, options) {
903
923
  const reveal = options?.reveal ?? true;
@@ -934,8 +954,11 @@ var useUiStore = create2()((set) => ({
934
954
  rightPanelCollapsed: false,
935
955
  activeRightTab: "situation",
936
956
  rightTabActivationId: 0,
957
+ rightPanelAutoJump: true,
958
+ rightPanelUnreadTabs: [],
937
959
  artifacts: [],
938
960
  activeArtifactIndex: -1,
961
+ previewUnreadArtifactKeys: [],
939
962
  theme: storedTheme,
940
963
  setLeftPanelSize: (size) => set({ leftPanelSize: size }),
941
964
  setRightPanelSize: (size) => set({ rightPanelSize: size }),
@@ -947,16 +970,60 @@ var useUiStore = create2()((set) => ({
947
970
  activeRightTab: tab,
948
971
  rightTabActivationId: state.rightTabActivationId + 1
949
972
  })),
973
+ setRightPanelAutoJump: (enabled) => set({ rightPanelAutoJump: enabled }),
974
+ markRightPanelTabUnread: (tab) => set((state) => ({ rightPanelUnreadTabs: addUnique(state.rightPanelUnreadTabs, tab) })),
975
+ clearRightPanelTabUnread: (tab) => set((state) => ({
976
+ rightPanelUnreadTabs: state.rightPanelUnreadTabs.filter((item) => item !== tab)
977
+ })),
978
+ markPreviewArtifactUnread: (key) => set((state) => ({
979
+ previewUnreadArtifactKeys: addUnique(state.previewUnreadArtifactKeys, key)
980
+ })),
981
+ clearPreviewArtifactUnread: (key) => set((state) => {
982
+ const previewUnreadArtifactKeys = state.previewUnreadArtifactKeys.filter((item) => item !== key);
983
+ return {
984
+ previewUnreadArtifactKeys,
985
+ rightPanelUnreadTabs: previewUnreadArtifactKeys.length === 0 ? state.rightPanelUnreadTabs.filter((tab) => tab !== "files") : state.rightPanelUnreadTabs
986
+ };
987
+ }),
988
+ activateLatestUnreadArtifact: () => set((state) => {
989
+ for (let index = state.artifacts.length - 1; index >= 0; index -= 1) {
990
+ const key = getPreviewTargetKey(state.artifacts[index]);
991
+ if (state.previewUnreadArtifactKeys.includes(key)) {
992
+ const previewUnreadArtifactKeys = state.previewUnreadArtifactKeys.filter((item) => item !== key);
993
+ return {
994
+ activeArtifactIndex: index,
995
+ previewUnreadArtifactKeys,
996
+ rightPanelUnreadTabs: previewUnreadArtifactKeys.length === 0 ? state.rightPanelUnreadTabs.filter((tab) => tab !== "files") : state.rightPanelUnreadTabs
997
+ };
998
+ }
999
+ }
1000
+ return state;
1001
+ }),
950
1002
  pushArtifact: (target) => set((state) => upsertArtifactState(state, target)),
951
1003
  upsertArtifact: (target, options) => set((state) => upsertArtifactState(state, target, options)),
952
- setActiveArtifact: (index) => set({ activeArtifactIndex: index }),
1004
+ setActiveArtifact: (index) => set((state) => {
1005
+ const artifact = state.artifacts[index];
1006
+ const key = artifact ? getPreviewTargetKey(artifact) : null;
1007
+ if (!key) return { activeArtifactIndex: index };
1008
+ const previewUnreadArtifactKeys = state.previewUnreadArtifactKeys.filter((item) => item !== key);
1009
+ return {
1010
+ activeArtifactIndex: index,
1011
+ previewUnreadArtifactKeys,
1012
+ rightPanelUnreadTabs: previewUnreadArtifactKeys.length === 0 ? state.rightPanelUnreadTabs.filter((tab) => tab !== "files") : state.rightPanelUnreadTabs
1013
+ };
1014
+ }),
953
1015
  closeArtifact: (index) => set((state) => removeArtifactAtIndex(state, index)),
954
1016
  removeArtifactByKey: (key) => set((state) => {
955
1017
  const index = state.artifacts.findIndex((artifact) => (artifact.key ?? artifact.title) === key);
956
1018
  if (index < 0) return state;
957
1019
  return removeArtifactAtIndex(state, index);
958
1020
  }),
959
- clearArtifacts: () => set({ artifacts: [], activeArtifactIndex: -1 }),
1021
+ clearArtifacts: () => set((state) => ({
1022
+ artifacts: [],
1023
+ activeArtifactIndex: -1,
1024
+ previewUnreadArtifactKeys: [],
1025
+ rightPanelUnreadTabs: state.rightPanelUnreadTabs.filter((tab) => tab !== "files")
1026
+ })),
960
1027
  setPreviewTarget: (target) => set((state) => {
961
1028
  if (target === null) {
962
1029
  return { artifacts: [], activeArtifactIndex: -1 };
@@ -2313,6 +2380,7 @@ var AgentSocket = class {
2313
2380
  // biome-ignore lint/suspicious/noExplicitAny: event bridge normalizes mixed legacy payloads.
2314
2381
  socket;
2315
2382
  subscribedSession = null;
2383
+ attachedSessions = /* @__PURE__ */ new Set();
2316
2384
  previewArtifactsByToolCall = /* @__PURE__ */ new Map();
2317
2385
  deliveredBridgeKeys = /* @__PURE__ */ new Set();
2318
2386
  pendingReplayMessages = /* @__PURE__ */ new Map();
@@ -2322,6 +2390,7 @@ var AgentSocket = class {
2322
2390
  joinedSessions = /* @__PURE__ */ new Set();
2323
2391
  requestedJoins = /* @__PURE__ */ new Set();
2324
2392
  pendingJoins = /* @__PURE__ */ new Map();
2393
+ boardProjectRefCounts = /* @__PURE__ */ new Map();
2325
2394
  patchFlushHandle = null;
2326
2395
  patchFlushCancel = null;
2327
2396
  _ensureConnected() {
@@ -2560,21 +2629,30 @@ var AgentSocket = class {
2560
2629
  });
2561
2630
  const handleArtifact = (sessionId, data) => {
2562
2631
  if (_isHiddenPath(data.file_path)) return;
2632
+ if (sessionId !== this.subscribedSession) return;
2563
2633
  const type2 = resolveArtifactType(data.content_type);
2564
2634
  const filePath = `/api/sessions/${sessionId}/files/${encodeURIComponent(data.file_path)}`;
2565
2635
  const fileUrl = this.client.buildAuthedUrl(filePath);
2566
2636
  const content = type2 === "ppt" ? filePath : type2 === "image" || type2 === "pdf" || type2 === "docx" || type2 === "excel" ? fileUrl : data.content;
2567
- if (data.session_id != null && data.session_id === this.subscribedSession) {
2568
- useUiStore.getState().setActiveRightTab("preview");
2569
- }
2570
- useUiStore.getState().pushArtifact({
2637
+ const target = {
2571
2638
  type: type2,
2572
2639
  content,
2573
2640
  sourceUrl: type2 === "ppt" ? fileUrl : void 0,
2574
2641
  title: data.title,
2575
2642
  key: data.file_path,
2576
2643
  revision: Date.now()
2577
- });
2644
+ };
2645
+ const uiStore = useUiStore.getState();
2646
+ if (uiStore.rightPanelAutoJump) {
2647
+ uiStore.clearRightPanelTabUnread("files");
2648
+ uiStore.clearPreviewArtifactUnread(data.file_path);
2649
+ uiStore.setActiveRightTab("preview");
2650
+ uiStore.pushArtifact(target);
2651
+ } else {
2652
+ uiStore.upsertArtifact(target, { reveal: false, activate: false });
2653
+ uiStore.markRightPanelTabUnread("files");
2654
+ uiStore.markPreviewArtifactUnread(data.file_path);
2655
+ }
2578
2656
  };
2579
2657
  s.on("artifact:created", (data) => {
2580
2658
  const sessionId = this._resolveSessionId(data);
@@ -2624,14 +2702,26 @@ var AgentSocket = class {
2624
2702
  const sessionId = this._resolveSessionId(data);
2625
2703
  if (!sessionId) return;
2626
2704
  notifyWorkspaceFilesChanged(sessionId, data.file_path);
2705
+ if (sessionId !== this.subscribedSession) return;
2627
2706
  if (data.old_string != null && data.new_string != null) {
2628
- useUiStore.getState().pushArtifact({
2707
+ const target = {
2629
2708
  type: "diff",
2630
2709
  content: data.new_string,
2631
2710
  oldContent: data.old_string,
2632
2711
  title: data.title,
2633
2712
  key: data.file_path
2634
- });
2713
+ };
2714
+ const uiStore = useUiStore.getState();
2715
+ if (uiStore.rightPanelAutoJump) {
2716
+ uiStore.clearRightPanelTabUnread("files");
2717
+ uiStore.clearPreviewArtifactUnread(data.file_path);
2718
+ uiStore.setActiveRightTab("preview");
2719
+ uiStore.pushArtifact(target);
2720
+ } else {
2721
+ uiStore.upsertArtifact(target, { reveal: false, activate: false });
2722
+ uiStore.markRightPanelTabUnread("files");
2723
+ uiStore.markPreviewArtifactUnread(data.file_path);
2724
+ }
2635
2725
  return;
2636
2726
  }
2637
2727
  handleArtifact(sessionId, data);
@@ -2649,6 +2739,11 @@ var AgentSocket = class {
2649
2739
  useSessionStore.getState().setActiveSession(sessionId);
2650
2740
  void this._ensureJoined(sessionId);
2651
2741
  }
2742
+ for (const attached of this.attachedSessions) {
2743
+ if (attached !== sessionId) {
2744
+ this.socket.emit("session:subscribe", { session_id: attached, mode: "status" });
2745
+ }
2746
+ }
2652
2747
  });
2653
2748
  this.socket.on("connect_error", (err) => {
2654
2749
  useConnectionStore.getState().markDisconnected();
@@ -2688,6 +2783,20 @@ var AgentSocket = class {
2688
2783
  });
2689
2784
  continue;
2690
2785
  }
2786
+ if (block.content.action.startsWith("solution.creator.")) {
2787
+ if (typeof window !== "undefined") {
2788
+ window.dispatchEvent(
2789
+ new CustomEvent("blade:solution-creator-bridge", {
2790
+ detail: {
2791
+ sessionId,
2792
+ action: block.content.action,
2793
+ payload: block.content.payload
2794
+ }
2795
+ })
2796
+ );
2797
+ }
2798
+ continue;
2799
+ }
2691
2800
  const deliveryKey = buildToolBridgeDeliveryKey(sessionId, turn, block);
2692
2801
  if (this.deliveredBridgeKeys.has(deliveryKey)) {
2693
2802
  continue;
@@ -2817,10 +2926,22 @@ var AgentSocket = class {
2817
2926
  }
2818
2927
  subscribeAgentBoardProject(projectId) {
2819
2928
  this._ensureConnected();
2820
- this.socket.emit("agent-board:project:subscribe", { project_id: Number(projectId) });
2929
+ const id = Number(projectId);
2930
+ const prev = this.boardProjectRefCounts.get(id) ?? 0;
2931
+ this.boardProjectRefCounts.set(id, prev + 1);
2932
+ if (prev === 0) {
2933
+ this.socket.emit("agent-board:project:subscribe", { project_id: id });
2934
+ }
2821
2935
  }
2822
2936
  unsubscribeAgentBoardProject(projectId) {
2823
- this.socket.emit("agent-board:project:unsubscribe", { project_id: Number(projectId) });
2937
+ const id = Number(projectId);
2938
+ const prev = this.boardProjectRefCounts.get(id) ?? 0;
2939
+ if (prev <= 1) {
2940
+ this.boardProjectRefCounts.delete(id);
2941
+ this.socket.emit("agent-board:project:unsubscribe", { project_id: id });
2942
+ } else {
2943
+ this.boardProjectRefCounts.set(id, prev - 1);
2944
+ }
2824
2945
  }
2825
2946
  onAgentBoardTaskChanged(handler) {
2826
2947
  this.socket.on("agent-board:board-task:changed", handler);
@@ -2855,11 +2976,18 @@ var AgentSocket = class {
2855
2976
  * 前端,卡片就会停留在乐观写入的"运行中"态。
2856
2977
  *
2857
2978
  * 幂等:后端 session:subscribe handler 只做 enter_room,重复 emit 无副作用。
2979
+ * 同时把 sessionId 记到 attachedSessions,连接断开重连时一并重新订阅,
2980
+ * 避免长会话期间断网后再回来时丢掉该 session 的 turn 事件。
2858
2981
  */
2859
2982
  attachSession(sessionId) {
2860
- void this._ensureJoined(sessionId);
2983
+ this.attachedSessions.add(sessionId);
2984
+ void this._ensureJoined(sessionId, "status");
2861
2985
  }
2862
- _ensureJoined(sessionId) {
2986
+ _ensureJoined(sessionId, mode = "full") {
2987
+ if (mode === "status") {
2988
+ this.socket.emit("session:subscribe", { session_id: sessionId, mode: "status" });
2989
+ return Promise.resolve();
2990
+ }
2863
2991
  if (this.joinedSessions.has(sessionId)) {
2864
2992
  return Promise.resolve();
2865
2993
  }
@@ -3264,4 +3392,4 @@ export {
3264
3392
  bootstrapBladeClient,
3265
3393
  getBootstrappedClient
3266
3394
  };
3267
- //# sourceMappingURL=chunk-II2PTBJI.js.map
3395
+ //# sourceMappingURL=chunk-U7Y7GRF6.js.map