@stigmer/react 0.2.0 → 0.2.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 (36) hide show
  1. package/composer/SessionComposer.d.ts.map +1 -1
  2. package/composer/SessionComposer.js +14 -5
  3. package/composer/SessionComposer.js.map +1 -1
  4. package/index.d.ts +2 -2
  5. package/index.d.ts.map +1 -1
  6. package/index.js +1 -1
  7. package/index.js.map +1 -1
  8. package/package.json +4 -4
  9. package/runner/RunnerFileBrowser.d.ts +33 -0
  10. package/runner/RunnerFileBrowser.d.ts.map +1 -0
  11. package/runner/RunnerFileBrowser.js +86 -0
  12. package/runner/RunnerFileBrowser.js.map +1 -0
  13. package/runner/__tests__/useRunnerFileBrowser.test.d.ts +2 -0
  14. package/runner/__tests__/useRunnerFileBrowser.test.d.ts.map +1 -0
  15. package/runner/__tests__/useRunnerFileBrowser.test.js +179 -0
  16. package/runner/__tests__/useRunnerFileBrowser.test.js.map +1 -0
  17. package/runner/index.d.ts +4 -0
  18. package/runner/index.d.ts.map +1 -1
  19. package/runner/index.js +2 -0
  20. package/runner/index.js.map +1 -1
  21. package/runner/useRunnerFileBrowser.d.ts +78 -0
  22. package/runner/useRunnerFileBrowser.d.ts.map +1 -0
  23. package/runner/useRunnerFileBrowser.js +191 -0
  24. package/runner/useRunnerFileBrowser.js.map +1 -0
  25. package/src/composer/SessionComposer.tsx +17 -5
  26. package/src/index.ts +5 -0
  27. package/src/runner/RunnerFileBrowser.tsx +384 -0
  28. package/src/runner/__tests__/useRunnerFileBrowser.test.tsx +256 -0
  29. package/src/runner/index.ts +9 -0
  30. package/src/runner/useRunnerFileBrowser.ts +308 -0
  31. package/src/workspace/WorkspaceEditor.tsx +86 -138
  32. package/styles.css +1 -1
  33. package/workspace/WorkspaceEditor.d.ts +30 -35
  34. package/workspace/WorkspaceEditor.d.ts.map +1 -1
  35. package/workspace/WorkspaceEditor.js +39 -48
  36. package/workspace/WorkspaceEditor.js.map +1 -1
@@ -0,0 +1,179 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { describe, it, expect, vi, beforeEach } from "vitest";
3
+ import { renderHook, act, waitFor } from "@testing-library/react";
4
+ import { StigmerContext } from "../../context";
5
+ import { useRunnerFileBrowser } from "../useRunnerFileBrowser";
6
+ function buildListDirectoryResponse(resolvedPath, entries, homeDirectory = "/home/user", currentDirectory = "/home/user/projects") {
7
+ return {
8
+ requestId: "req-1",
9
+ result: {
10
+ case: "listDirectory",
11
+ value: {
12
+ resolvedPath,
13
+ entries: entries.map((e) => ({
14
+ name: e.name,
15
+ isDirectory: e.isDirectory,
16
+ isHidden: e.isHidden,
17
+ $typeName: "ai.stigmer.agentic.runner.v1.DirectoryEntry",
18
+ })),
19
+ homeDirectory,
20
+ currentDirectory,
21
+ $typeName: "ai.stigmer.agentic.runner.v1.ListDirectoryResponse",
22
+ },
23
+ },
24
+ $typeName: "ai.stigmer.agentic.runner.v1.RunnerCommandResponse",
25
+ };
26
+ }
27
+ function buildErrorResponse(message) {
28
+ return {
29
+ requestId: "req-1",
30
+ result: {
31
+ case: "error",
32
+ value: {
33
+ message,
34
+ $typeName: "ai.stigmer.agentic.runner.v1.RunnerCommandError",
35
+ },
36
+ },
37
+ $typeName: "ai.stigmer.agentic.runner.v1.RunnerCommandResponse",
38
+ };
39
+ }
40
+ function buildMockClient(sendCommand) {
41
+ return {
42
+ runner: { sendCommand },
43
+ };
44
+ }
45
+ function makeWrapper(client) {
46
+ return ({ children }) => (_jsx(StigmerContext.Provider, { value: client, children: children }));
47
+ }
48
+ describe("useRunnerFileBrowser", () => {
49
+ let sendCommandMock;
50
+ let client;
51
+ beforeEach(() => {
52
+ sendCommandMock = vi.fn();
53
+ client = buildMockClient(sendCommandMock);
54
+ });
55
+ it("fetches home directory on initial mount with runnerId", async () => {
56
+ sendCommandMock.mockResolvedValueOnce(buildListDirectoryResponse("/home/user", [
57
+ { name: "projects", isDirectory: true, isHidden: false },
58
+ { name: ".config", isDirectory: true, isHidden: true },
59
+ { name: ".bashrc", isDirectory: false, isHidden: true },
60
+ ]));
61
+ const { result } = renderHook(() => useRunnerFileBrowser("rnr_1"), {
62
+ wrapper: makeWrapper(client),
63
+ });
64
+ await waitFor(() => {
65
+ expect(result.current.isLoading).toBe(false);
66
+ });
67
+ expect(sendCommandMock).toHaveBeenCalledOnce();
68
+ expect(result.current.currentPath).toBe("/home/user");
69
+ expect(result.current.entries).toHaveLength(3);
70
+ expect(result.current.homeDirectory).toBe("/home/user");
71
+ expect(result.current.currentDirectory).toBe("/home/user/projects");
72
+ expect(result.current.segments).toHaveLength(3);
73
+ expect(result.current.segments[0].name).toBe("/");
74
+ expect(result.current.segments[2].name).toBe("user");
75
+ });
76
+ it("does not fetch when runnerId is null", () => {
77
+ renderHook(() => useRunnerFileBrowser(null), {
78
+ wrapper: makeWrapper(client),
79
+ });
80
+ expect(sendCommandMock).not.toHaveBeenCalled();
81
+ });
82
+ it("navigates into a child directory", async () => {
83
+ sendCommandMock
84
+ .mockResolvedValueOnce(buildListDirectoryResponse("/home/user", [
85
+ { name: "projects", isDirectory: true, isHidden: false },
86
+ ]))
87
+ .mockResolvedValueOnce(buildListDirectoryResponse("/home/user/projects", [
88
+ { name: "my-app", isDirectory: true, isHidden: false },
89
+ ]));
90
+ const { result } = renderHook(() => useRunnerFileBrowser("rnr_1"), {
91
+ wrapper: makeWrapper(client),
92
+ });
93
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
94
+ await act(async () => {
95
+ result.current.navigateTo("projects");
96
+ });
97
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
98
+ expect(result.current.currentPath).toBe("/home/user/projects");
99
+ expect(result.current.entries).toHaveLength(1);
100
+ expect(result.current.entries[0].name).toBe("my-app");
101
+ });
102
+ it("navigates up to parent directory", async () => {
103
+ sendCommandMock
104
+ .mockResolvedValueOnce(buildListDirectoryResponse("/home/user/projects", []))
105
+ .mockResolvedValueOnce(buildListDirectoryResponse("/home/user", [
106
+ { name: "projects", isDirectory: true, isHidden: false },
107
+ ]));
108
+ const { result } = renderHook(() => useRunnerFileBrowser("rnr_1"), {
109
+ wrapper: makeWrapper(client),
110
+ });
111
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
112
+ await act(async () => {
113
+ result.current.navigateUp();
114
+ });
115
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
116
+ expect(result.current.currentPath).toBe("/home/user");
117
+ });
118
+ it("handles runner error responses", async () => {
119
+ sendCommandMock.mockResolvedValueOnce(buildErrorResponse("permission denied: /root"));
120
+ const { result } = renderHook(() => useRunnerFileBrowser("rnr_1"), {
121
+ wrapper: makeWrapper(client),
122
+ });
123
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
124
+ expect(result.current.error).not.toBeNull();
125
+ expect(result.current.error.message).toBe("permission denied: /root");
126
+ });
127
+ it("handles network errors", async () => {
128
+ sendCommandMock.mockRejectedValueOnce(new Error("runner unavailable"));
129
+ const { result } = renderHook(() => useRunnerFileBrowser("rnr_1"), {
130
+ wrapper: makeWrapper(client),
131
+ });
132
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
133
+ expect(result.current.error).not.toBeNull();
134
+ expect(result.current.error.message).toBe("runner unavailable");
135
+ });
136
+ it("toggles hidden files", async () => {
137
+ sendCommandMock.mockResolvedValueOnce(buildListDirectoryResponse("/home/user", []));
138
+ const { result } = renderHook(() => useRunnerFileBrowser("rnr_1"), {
139
+ wrapper: makeWrapper(client),
140
+ });
141
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
142
+ expect(result.current.showHidden).toBe(false);
143
+ act(() => {
144
+ result.current.toggleHidden();
145
+ });
146
+ expect(result.current.showHidden).toBe(true);
147
+ act(() => {
148
+ result.current.toggleHidden();
149
+ });
150
+ expect(result.current.showHidden).toBe(false);
151
+ });
152
+ it("retries the last failed request", async () => {
153
+ sendCommandMock
154
+ .mockRejectedValueOnce(new Error("timeout"))
155
+ .mockResolvedValueOnce(buildListDirectoryResponse("/home/user", []));
156
+ const { result } = renderHook(() => useRunnerFileBrowser("rnr_1"), {
157
+ wrapper: makeWrapper(client),
158
+ });
159
+ await waitFor(() => expect(result.current.error).not.toBeNull());
160
+ await act(async () => {
161
+ result.current.retry();
162
+ });
163
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
164
+ expect(result.current.error).toBeNull();
165
+ expect(result.current.currentPath).toBe("/home/user");
166
+ expect(sendCommandMock).toHaveBeenCalledTimes(2);
167
+ });
168
+ it("reports isAtRoot correctly", async () => {
169
+ sendCommandMock.mockResolvedValueOnce(buildListDirectoryResponse("/", [
170
+ { name: "home", isDirectory: true, isHidden: false },
171
+ ]));
172
+ const { result } = renderHook(() => useRunnerFileBrowser("rnr_1"), {
173
+ wrapper: makeWrapper(client),
174
+ });
175
+ await waitFor(() => expect(result.current.isLoading).toBe(false));
176
+ expect(result.current.isAtRoot).toBe(true);
177
+ });
178
+ });
179
+ //# sourceMappingURL=useRunnerFileBrowser.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRunnerFileBrowser.test.js","sourceRoot":"","sources":["../../../src/runner/__tests__/useRunnerFileBrowser.test.tsx"],"names":[],"mappings":"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"}
package/runner/index.d.ts CHANGED
@@ -10,6 +10,10 @@ export { useDeleteRunner } from "./useDeleteRunner";
10
10
  export type { UseDeleteRunnerReturn } from "./useDeleteRunner";
11
11
  export { RunnerPicker } from "./RunnerPicker";
12
12
  export type { RunnerPickerProps } from "./RunnerPicker";
13
+ export { RunnerFileBrowser } from "./RunnerFileBrowser";
14
+ export type { RunnerFileBrowserProps } from "./RunnerFileBrowser";
15
+ export { useRunnerFileBrowser } from "./useRunnerFileBrowser";
16
+ export type { UseRunnerFileBrowserReturn, PathSegment, } from "./useRunnerFileBrowser";
13
17
  export { RunnerListPanel } from "./RunnerListPanel";
14
18
  export type { RunnerListPanelProps } from "./RunnerListPanel";
15
19
  export { phaseLabel, phaseDotColor, isActivePhase, isTransitionalPhase, PHASE_SORT_ORDER, } from "./phase";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runner/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EACV,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EACV,2BAA2B,EAC3B,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EACV,gBAAgB,EAChB,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EACV,eAAe,EACf,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE/D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,OAAO,EACL,UAAU,EACV,aAAa,EACb,aAAa,EACb,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runner/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EACV,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EACV,2BAA2B,EAC3B,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EACV,gBAAgB,EAChB,yBAAyB,GAC1B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EACV,eAAe,EACf,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE/D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAElE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EACV,0BAA0B,EAC1B,WAAW,GACZ,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,OAAO,EACL,UAAU,EACV,aAAa,EACb,aAAa,EACb,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,SAAS,CAAC"}
package/runner/index.js CHANGED
@@ -4,6 +4,8 @@ export { useRunnerCredential } from "./useRunnerCredential";
4
4
  export { useStopRunner } from "./useStopRunner";
5
5
  export { useDeleteRunner } from "./useDeleteRunner";
6
6
  export { RunnerPicker } from "./RunnerPicker";
7
+ export { RunnerFileBrowser } from "./RunnerFileBrowser";
8
+ export { useRunnerFileBrowser } from "./useRunnerFileBrowser";
7
9
  export { RunnerListPanel } from "./RunnerListPanel";
8
10
  export { phaseLabel, phaseDotColor, isActivePhase, isTransitionalPhase, PHASE_SORT_ORDER, } from "./phase";
9
11
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/runner/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAMhD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAO9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAM5D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAMhD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGpD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGpD,OAAO,EACL,UAAU,EACV,aAAa,EACb,aAAa,EACb,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/runner/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAMhD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAO9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAM5D,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAMhD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGpD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAG9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAM9D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGpD,OAAO,EACL,UAAU,EACV,aAAa,EACb,aAAa,EACb,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,SAAS,CAAC"}
@@ -0,0 +1,78 @@
1
+ import { type DirectoryEntry } from "@stigmer/protos/ai/stigmer/agentic/runner/v1/io_pb";
2
+ /** A single segment of the breadcrumb path bar. */
3
+ export interface PathSegment {
4
+ /** Display name (directory name, or "/" for root). */
5
+ readonly name: string;
6
+ /** Absolute path up to and including this segment. */
7
+ readonly path: string;
8
+ }
9
+ /** Return value of {@link useRunnerFileBrowser}. */
10
+ export interface UseRunnerFileBrowserReturn {
11
+ /** Current resolved absolute path. */
12
+ readonly currentPath: string;
13
+ /** Directory entries for the current path. */
14
+ readonly entries: readonly DirectoryEntry[];
15
+ /** Breadcrumb segments for the current path. */
16
+ readonly segments: readonly PathSegment[];
17
+ /** Runner's home directory (enables Home shortcut). */
18
+ readonly homeDirectory: string;
19
+ /** Runner process's current working directory (enables CWD shortcut). */
20
+ readonly currentDirectory: string;
21
+ /** Whether hidden files are shown. */
22
+ readonly showHidden: boolean;
23
+ /** Toggle hidden file visibility. */
24
+ readonly toggleHidden: () => void;
25
+ /** True while a directory listing is in flight. */
26
+ readonly isLoading: boolean;
27
+ /** Error from the last navigation attempt. */
28
+ readonly error: Error | null;
29
+ /** Navigate into a child directory by name. */
30
+ readonly navigateTo: (name: string) => void;
31
+ /** Navigate to an absolute path. */
32
+ readonly navigateToPath: (path: string) => void;
33
+ /** Navigate to the parent directory. */
34
+ readonly navigateUp: () => void;
35
+ /** Navigate to the runner's home directory. */
36
+ readonly navigateHome: () => void;
37
+ /** Navigate to the runner's current working directory. */
38
+ readonly navigateCwd: () => void;
39
+ /** Retry the last failed navigation. */
40
+ readonly retry: () => void;
41
+ /** True when at the filesystem root (no parent). */
42
+ readonly isAtRoot: boolean;
43
+ }
44
+ /**
45
+ * Behavior hook that drives a filesystem browser against a connected runner.
46
+ *
47
+ * Sends `ListDirectory` commands via the runner's bidi stream (through the
48
+ * `sendCommand` unary RPC) and manages navigation state, breadcrumbs,
49
+ * loading/error handling, and hidden file filtering.
50
+ *
51
+ * Designed for composition with {@link RunnerFileBrowser} but usable
52
+ * standalone by platform builders who want custom rendering.
53
+ *
54
+ * @param runnerId - ID of the runner to browse. When `null`, the hook
55
+ * is inert (no requests are made, entries are empty).
56
+ *
57
+ * @example
58
+ * ```tsx
59
+ * function MyFilePicker({ runnerId }: { runnerId: string }) {
60
+ * const browser = useRunnerFileBrowser(runnerId);
61
+ *
62
+ * return (
63
+ * <div>
64
+ * <p>Path: {browser.currentPath}</p>
65
+ * {browser.entries
66
+ * .filter(e => e.isDirectory)
67
+ * .map(e => (
68
+ * <button key={e.name} onClick={() => browser.navigateTo(e.name)}>
69
+ * {e.name}
70
+ * </button>
71
+ * ))}
72
+ * </div>
73
+ * );
74
+ * }
75
+ * ```
76
+ */
77
+ export declare function useRunnerFileBrowser(runnerId: string | null): UseRunnerFileBrowserReturn;
78
+ //# sourceMappingURL=useRunnerFileBrowser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRunnerFileBrowser.d.ts","sourceRoot":"","sources":["../../src/runner/useRunnerFileBrowser.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,oDAAoD,CAAC;AAI5D,mDAAmD;AACnD,MAAM,WAAW,WAAW;IAC1B,sDAAsD;IACtD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,sDAAsD;IACtD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,oDAAoD;AACpD,MAAM,WAAW,0BAA0B;IACzC,sCAAsC;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,8CAA8C;IAC9C,QAAQ,CAAC,OAAO,EAAE,SAAS,cAAc,EAAE,CAAC;IAC5C,gDAAgD;IAChD,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IAC1C,uDAAuD;IACvD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,yEAAyE;IACzE,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,sCAAsC;IACtC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,qCAAqC;IACrC,QAAQ,CAAC,YAAY,EAAE,MAAM,IAAI,CAAC;IAClC,mDAAmD;IACnD,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC7B,+CAA+C;IAC/C,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,oCAAoC;IACpC,QAAQ,CAAC,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,wCAAwC;IACxC,QAAQ,CAAC,UAAU,EAAE,MAAM,IAAI,CAAC;IAChC,+CAA+C;IAC/C,QAAQ,CAAC,YAAY,EAAE,MAAM,IAAI,CAAC;IAClC,0DAA0D;IAC1D,QAAQ,CAAC,WAAW,EAAE,MAAM,IAAI,CAAC;IACjC,wCAAwC;IACxC,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC;IAC3B,oDAAoD;IACpD,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AA0FD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,GAAG,IAAI,GACtB,0BAA0B,CAgI5B"}
@@ -0,0 +1,191 @@
1
+ "use client";
2
+ import { useCallback, useEffect, useReducer, useRef } from "react";
3
+ import { create } from "@bufbuild/protobuf";
4
+ import { RunnerSendCommandInputSchema, ListDirectoryRequestSchema, } from "@stigmer/protos/ai/stigmer/agentic/runner/v1/io_pb";
5
+ import { useStigmer } from "../hooks";
6
+ import { toError } from "../internal/toError";
7
+ function reducer(state, action) {
8
+ switch (action.type) {
9
+ case "NAVIGATE":
10
+ return {
11
+ ...state,
12
+ requestedPath: action.path,
13
+ isLoading: true,
14
+ error: null,
15
+ };
16
+ case "SUCCESS":
17
+ return {
18
+ ...state,
19
+ currentPath: action.resolvedPath,
20
+ entries: action.entries,
21
+ homeDirectory: action.homeDirectory || state.homeDirectory,
22
+ currentDirectory: action.currentDirectory || state.currentDirectory,
23
+ isLoading: false,
24
+ error: null,
25
+ };
26
+ case "FAILURE":
27
+ return { ...state, isLoading: false, error: action.error };
28
+ case "TOGGLE_HIDDEN":
29
+ return { ...state, showHidden: !state.showHidden };
30
+ }
31
+ }
32
+ const INITIAL_STATE = {
33
+ currentPath: "",
34
+ entries: [],
35
+ homeDirectory: "",
36
+ currentDirectory: "",
37
+ showHidden: false,
38
+ isLoading: false,
39
+ error: null,
40
+ requestedPath: "",
41
+ };
42
+ // ---------------------------------------------------------------------------
43
+ // Path utilities
44
+ // ---------------------------------------------------------------------------
45
+ function buildSegments(path) {
46
+ if (!path)
47
+ return [];
48
+ const segments = [{ name: "/", path: "/" }];
49
+ const parts = path.split("/").filter(Boolean);
50
+ let accumulated = "";
51
+ for (const part of parts) {
52
+ accumulated += `/${part}`;
53
+ segments.push({ name: part, path: accumulated });
54
+ }
55
+ return segments;
56
+ }
57
+ function parentPath(path) {
58
+ if (!path || path === "/")
59
+ return "/";
60
+ const idx = path.lastIndexOf("/");
61
+ return idx <= 0 ? "/" : path.slice(0, idx);
62
+ }
63
+ // ---------------------------------------------------------------------------
64
+ // Hook
65
+ // ---------------------------------------------------------------------------
66
+ /**
67
+ * Behavior hook that drives a filesystem browser against a connected runner.
68
+ *
69
+ * Sends `ListDirectory` commands via the runner's bidi stream (through the
70
+ * `sendCommand` unary RPC) and manages navigation state, breadcrumbs,
71
+ * loading/error handling, and hidden file filtering.
72
+ *
73
+ * Designed for composition with {@link RunnerFileBrowser} but usable
74
+ * standalone by platform builders who want custom rendering.
75
+ *
76
+ * @param runnerId - ID of the runner to browse. When `null`, the hook
77
+ * is inert (no requests are made, entries are empty).
78
+ *
79
+ * @example
80
+ * ```tsx
81
+ * function MyFilePicker({ runnerId }: { runnerId: string }) {
82
+ * const browser = useRunnerFileBrowser(runnerId);
83
+ *
84
+ * return (
85
+ * <div>
86
+ * <p>Path: {browser.currentPath}</p>
87
+ * {browser.entries
88
+ * .filter(e => e.isDirectory)
89
+ * .map(e => (
90
+ * <button key={e.name} onClick={() => browser.navigateTo(e.name)}>
91
+ * {e.name}
92
+ * </button>
93
+ * ))}
94
+ * </div>
95
+ * );
96
+ * }
97
+ * ```
98
+ */
99
+ export function useRunnerFileBrowser(runnerId) {
100
+ const stigmer = useStigmer();
101
+ const [state, dispatch] = useReducer(reducer, INITIAL_STATE);
102
+ const requestIdRef = useRef(0);
103
+ const fetchDirectory = useCallback(async (path) => {
104
+ if (!runnerId)
105
+ return;
106
+ const id = ++requestIdRef.current;
107
+ dispatch({ type: "NAVIGATE", path });
108
+ try {
109
+ const response = await stigmer.runner.sendCommand(create(RunnerSendCommandInputSchema, {
110
+ runnerId,
111
+ command: {
112
+ case: "listDirectory",
113
+ value: create(ListDirectoryRequestSchema, { path }),
114
+ },
115
+ }));
116
+ // Stale response guard — a newer navigation has started.
117
+ if (id !== requestIdRef.current)
118
+ return;
119
+ if (response.result.case === "error") {
120
+ dispatch({
121
+ type: "FAILURE",
122
+ error: new Error(response.result.value.message),
123
+ });
124
+ return;
125
+ }
126
+ if (response.result.case === "listDirectory") {
127
+ const listing = response.result.value;
128
+ dispatch({
129
+ type: "SUCCESS",
130
+ resolvedPath: listing.resolvedPath,
131
+ entries: listing.entries,
132
+ homeDirectory: listing.homeDirectory,
133
+ currentDirectory: listing.currentDirectory,
134
+ });
135
+ }
136
+ }
137
+ catch (err) {
138
+ if (id !== requestIdRef.current)
139
+ return;
140
+ dispatch({ type: "FAILURE", error: toError(err) });
141
+ }
142
+ }, [runnerId, stigmer]);
143
+ // Initial load: fetch home directory when runnerId becomes available.
144
+ const initializedForRef = useRef(null);
145
+ useEffect(() => {
146
+ if (!runnerId) {
147
+ initializedForRef.current = null;
148
+ return;
149
+ }
150
+ if (initializedForRef.current !== runnerId) {
151
+ initializedForRef.current = runnerId;
152
+ fetchDirectory("");
153
+ }
154
+ }, [runnerId, fetchDirectory]);
155
+ const navigateTo = useCallback((name) => {
156
+ const next = state.currentPath === "/"
157
+ ? `/${name}`
158
+ : `${state.currentPath}/${name}`;
159
+ fetchDirectory(next);
160
+ }, [state.currentPath, fetchDirectory]);
161
+ const navigateToPath = useCallback((path) => fetchDirectory(path), [fetchDirectory]);
162
+ const navigateUp = useCallback(() => fetchDirectory(parentPath(state.currentPath)), [state.currentPath, fetchDirectory]);
163
+ const navigateHome = useCallback(() => fetchDirectory(state.homeDirectory || "~"), [state.homeDirectory, fetchDirectory]);
164
+ const navigateCwd = useCallback(() => {
165
+ if (state.currentDirectory)
166
+ fetchDirectory(state.currentDirectory);
167
+ }, [state.currentDirectory, fetchDirectory]);
168
+ const retry = useCallback(() => fetchDirectory(state.requestedPath), [state.requestedPath, fetchDirectory]);
169
+ const toggleHidden = useCallback(() => dispatch({ type: "TOGGLE_HIDDEN" }), []);
170
+ const segments = buildSegments(state.currentPath);
171
+ const isAtRoot = state.currentPath === "/";
172
+ return {
173
+ currentPath: state.currentPath,
174
+ entries: state.entries,
175
+ segments,
176
+ homeDirectory: state.homeDirectory,
177
+ currentDirectory: state.currentDirectory,
178
+ showHidden: state.showHidden,
179
+ toggleHidden,
180
+ isLoading: state.isLoading,
181
+ error: state.error,
182
+ navigateTo,
183
+ navigateToPath,
184
+ navigateUp,
185
+ navigateHome,
186
+ navigateCwd,
187
+ retry,
188
+ isAtRoot,
189
+ };
190
+ }
191
+ //# sourceMappingURL=useRunnerFileBrowser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRunnerFileBrowser.js","sourceRoot":"","sources":["../../src/runner/useRunnerFileBrowser.ts"],"names":[],"mappings":"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"}
@@ -402,18 +402,29 @@ export function SessionComposer({
402
402
  const showAttach = enableAttachments;
403
403
 
404
404
  // ---------------------------------------------------------------------------
405
- // Runner name resolution — for the workspace contextual hint
405
+ // Runner resolution — name for contextual hint + ID for file browsing
406
406
  // ---------------------------------------------------------------------------
407
407
 
408
- const { runners: runnerListForName } = useRunnerList(
409
- showRunner && runnerId ? (org ?? null) : null,
408
+ const needsRunnerList = showRunner && (runnerId || (showWorkspace && enableLocal));
409
+
410
+ const { runners: runnerListForBrowse } = useRunnerList(
411
+ needsRunnerList ? (org ?? null) : null,
410
412
  );
411
413
 
412
414
  const selectedRunnerName = useMemo(() => {
413
415
  if (!runnerId) return undefined;
414
- const runner = runnerListForName.find((r) => r.metadata?.id === runnerId);
416
+ const runner = runnerListForBrowse.find((r) => r.metadata?.id === runnerId);
415
417
  return runner?.metadata?.name;
416
- }, [runnerId, runnerListForName]);
418
+ }, [runnerId, runnerListForBrowse]);
419
+
420
+ const browseRunnerId = useMemo(() => {
421
+ if (runnerId) return runnerId;
422
+ if (!enableLocal) return null;
423
+ const active = runnerListForBrowse.find((r) =>
424
+ isActivePhase(r.status?.phase ?? RunnerPhase.UNSPECIFIED),
425
+ );
426
+ return active?.metadata?.id ?? null;
427
+ }, [runnerId, enableLocal, runnerListForBrowse]);
417
428
 
418
429
  // ---------------------------------------------------------------------------
419
430
  // Configure menu state — drives the Tier 2 drill-down popover
@@ -1351,6 +1362,7 @@ export function SessionComposer({
1351
1362
  gitHubConnection={gitHubConnection}
1352
1363
  enableGitHub={enableGitHub}
1353
1364
  enableLocal={enableLocal}
1365
+ runnerId={browseRunnerId}
1354
1366
  onBrowseLocalFolder={onBrowseLocalFolder}
1355
1367
  runnerName={selectedRunnerName}
1356
1368
  />
package/src/index.ts CHANGED
@@ -685,7 +685,9 @@ export {
685
685
  useRunnerCredential,
686
686
  useStopRunner,
687
687
  useDeleteRunner,
688
+ useRunnerFileBrowser,
688
689
  RunnerPicker,
690
+ RunnerFileBrowser,
689
691
  RunnerListPanel,
690
692
  phaseLabel,
691
693
  phaseDotColor,
@@ -704,6 +706,9 @@ export type {
704
706
  StopRunnerInput,
705
707
  UseStopRunnerReturn,
706
708
  UseDeleteRunnerReturn,
709
+ UseRunnerFileBrowserReturn,
710
+ PathSegment,
707
711
  RunnerPickerProps,
712
+ RunnerFileBrowserProps,
708
713
  RunnerListPanelProps,
709
714
  } from "./runner";