@loopstack/remote-file-explorer-module 0.22.3 → 0.22.5
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.
- package/README.md +67 -0
- package/dist/controllers/remote-file-explorer.controller.d.ts +4 -4
- package/dist/controllers/remote-file-explorer.controller.d.ts.map +1 -1
- package/dist/controllers/remote-file-explorer.controller.js +2 -2
- package/dist/controllers/remote-file-explorer.controller.js.map +1 -1
- package/dist/remote-file-explorer.module.js +2 -2
- package/dist/remote-file-explorer.module.js.map +1 -1
- package/package.json +7 -10
- package/src/controllers/index.ts +0 -1
- package/src/controllers/remote-file-explorer.controller.ts +0 -55
- package/src/index.ts +0 -2
- package/src/remote-file-explorer.module.ts +0 -12
package/README.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# @loopstack/remote-file-explorer-module
|
|
2
|
+
|
|
3
|
+
> A module for the [Loopstack AI](https://loopstack.ai) automation framework.
|
|
4
|
+
|
|
5
|
+
REST endpoints for browsing files in a Loopstack remote workspace. A thin proxy over `@loopstack/remote-client` designed to back a file-tree UI.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
When a UI (like the Loopstack Studio) needs to render a file tree and file contents for a remote workspace, it talks to `RemoteFileExplorerController`. The controller forwards the request to the workspace's remote agent via `RemoteClient`. No workflow tools are exposed by this module — if you want to read files from a workflow, use `ReadTool` / `GlobTool` from `@loopstack/remote-client` instead.
|
|
10
|
+
|
|
11
|
+
By using this module you'll get:
|
|
12
|
+
|
|
13
|
+
- **`RemoteFileExplorerController`** with two endpoints:
|
|
14
|
+
- `GET /remote-file-explorer/tree?path=...` — returns the directory tree
|
|
15
|
+
- `GET /remote-file-explorer/content?path=...` — returns the contents of a single file
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npm install @loopstack/remote-file-explorer-module
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Register the module:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { RemoteFileExplorerModule } from '@loopstack/remote-file-explorer-module';
|
|
27
|
+
|
|
28
|
+
@Module({
|
|
29
|
+
imports: [RemoteFileExplorerModule /* ... */],
|
|
30
|
+
})
|
|
31
|
+
export class AppModule {}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`RemoteFileExplorerModule` depends on `RemoteClientModule`, `LoopCoreModule`, and uses `WorkspaceEntity` via TypeORM.
|
|
35
|
+
|
|
36
|
+
## How It Works
|
|
37
|
+
|
|
38
|
+
Once registered, the two endpoints are available on your backend. They resolve the workspace (from query / body params) and proxy to the workspace's remote agent:
|
|
39
|
+
|
|
40
|
+
```http
|
|
41
|
+
GET /remote-file-explorer/tree?workspaceId=<id>&path=src
|
|
42
|
+
GET /remote-file-explorer/content?workspaceId=<id>&path=src/index.ts
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
See `src/controllers/remote-file-explorer.controller.ts` for the exact shape of each response.
|
|
46
|
+
|
|
47
|
+
## Public API
|
|
48
|
+
|
|
49
|
+
- **Module:** `RemoteFileExplorerModule`
|
|
50
|
+
- **Controller:** `RemoteFileExplorerController`
|
|
51
|
+
|
|
52
|
+
## Dependencies
|
|
53
|
+
|
|
54
|
+
- `@loopstack/common`, `@loopstack/core` — framework
|
|
55
|
+
- `@loopstack/remote-client` — underlying remote file access
|
|
56
|
+
- `@nestjs/typeorm`, `typeorm` — workspace persistence
|
|
57
|
+
|
|
58
|
+
## About
|
|
59
|
+
|
|
60
|
+
Author: [Jakob Klippel](https://www.linkedin.com/in/jakob-klippel/)
|
|
61
|
+
|
|
62
|
+
License: MIT
|
|
63
|
+
|
|
64
|
+
### Additional Resources
|
|
65
|
+
|
|
66
|
+
- [Loopstack Documentation](https://loopstack.ai/docs)
|
|
67
|
+
- Find more Loopstack modules in the [Loopstack Registry](https://loopstack.ai/registry)
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Repository } from 'typeorm';
|
|
2
2
|
import { CurrentUserInterface, WorkspaceEntity } from '@loopstack/common';
|
|
3
|
-
import {
|
|
3
|
+
import { RemoteClient } from '@loopstack/remote-client';
|
|
4
4
|
export declare class RemoteFileExplorerController {
|
|
5
5
|
private readonly remoteAgentClient;
|
|
6
6
|
private readonly workspaceRepository;
|
|
7
|
-
constructor(remoteAgentClient:
|
|
7
|
+
constructor(remoteAgentClient: RemoteClient, workspaceRepository: Repository<WorkspaceEntity>);
|
|
8
8
|
private getAgentUrl;
|
|
9
|
-
getFileTree(workspaceId: string, basePath: string | undefined, user: CurrentUserInterface): Promise<import("@loopstack/remote-
|
|
10
|
-
readFile(workspaceId: string, filePath: string, user: CurrentUserInterface): Promise<import("@loopstack/remote-
|
|
9
|
+
getFileTree(workspaceId: string, basePath: string | undefined, user: CurrentUserInterface): Promise<import("@loopstack/remote-client/dist/services/remote-client.service").FileTreeNode[]>;
|
|
10
|
+
readFile(workspaceId: string, filePath: string, user: CurrentUserInterface): Promise<import("@loopstack/remote-client").FileReadResponse>;
|
|
11
11
|
}
|
|
12
12
|
//# sourceMappingURL=remote-file-explorer.controller.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-file-explorer.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/remote-file-explorer.controller.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAe,oBAAoB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACvF,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"remote-file-explorer.controller.d.ts","sourceRoot":"","sources":["../../src/controllers/remote-file-explorer.controller.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAe,oBAAoB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACvF,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD,qBAGa,4BAA4B;IAErC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAElC,OAAO,CAAC,QAAQ,CAAC,mBAAmB;gBAFnB,iBAAiB,EAAE,YAAY,EAE/B,mBAAmB,EAAE,UAAU,CAAC,eAAe,CAAC;YAGrD,WAAW;IAmBnB,WAAW,CACO,WAAW,EAAE,MAAM,EAC1B,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,IAAI,EAAE,oBAAoB;IAOrC,QAAQ,CACU,WAAW,EAAE,MAAM,EAC1B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,oBAAoB;CAK5C"}
|
|
@@ -18,7 +18,7 @@ const swagger_1 = require("@nestjs/swagger");
|
|
|
18
18
|
const typeorm_1 = require("@nestjs/typeorm");
|
|
19
19
|
const typeorm_2 = require("typeorm");
|
|
20
20
|
const common_2 = require("@loopstack/common");
|
|
21
|
-
const
|
|
21
|
+
const remote_client_1 = require("@loopstack/remote-client");
|
|
22
22
|
let RemoteFileExplorerController = class RemoteFileExplorerController {
|
|
23
23
|
remoteAgentClient;
|
|
24
24
|
workspaceRepository;
|
|
@@ -73,7 +73,7 @@ exports.RemoteFileExplorerController = RemoteFileExplorerController = __decorate
|
|
|
73
73
|
(0, common_1.UsePipes)(new common_1.ValidationPipe({ transform: true, whitelist: true, forbidNonWhitelisted: true })),
|
|
74
74
|
(0, common_1.Controller)('api/v1/workspaces/:workspaceId/files'),
|
|
75
75
|
__param(1, (0, typeorm_1.InjectRepository)(common_2.WorkspaceEntity)),
|
|
76
|
-
__metadata("design:paramtypes", [
|
|
76
|
+
__metadata("design:paramtypes", [remote_client_1.RemoteClient,
|
|
77
77
|
typeorm_2.Repository])
|
|
78
78
|
], RemoteFileExplorerController);
|
|
79
79
|
//# sourceMappingURL=remote-file-explorer.controller.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-file-explorer.controller.js","sourceRoot":"","sources":["../../src/controllers/remote-file-explorer.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAA4G;AAC5G,6CAA0C;AAC1C,6CAAmD;AACnD,qCAAqC;AACrC,8CAAuF;AACvF,
|
|
1
|
+
{"version":3,"file":"remote-file-explorer.controller.js","sourceRoot":"","sources":["../../src/controllers/remote-file-explorer.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAA4G;AAC5G,6CAA0C;AAC1C,6CAAmD;AACnD,qCAAqC;AACrC,8CAAuF;AACvF,4DAAwD;AAKjD,IAAM,4BAA4B,GAAlC,MAAM,4BAA4B;IAEpB;IAEA;IAHnB,YACmB,iBAA+B,EAE/B,mBAAgD;QAFhD,sBAAiB,GAAjB,iBAAiB,CAAc;QAE/B,wBAAmB,GAAnB,mBAAmB,CAA6B;IAChE,CAAC;IAEI,KAAK,CAAC,WAAW,CAAC,WAAmB,EAAE,MAAc;QAC3D,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC;YACvD,KAAK,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE;YAC7C,SAAS,EAAE,CAAC,cAAc,CAAC;SAC5B,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,0BAAiB,CAAC,qBAAqB,WAAW,YAAY,CAAC,CAAC;QAC5E,CAAC;QAED,MAAM,WAAW,GAAG,SAAS,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QACtE,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,CAAC;YAC3B,MAAM,IAAI,0BAAiB,CAAC,kDAAkD,WAAW,EAAE,CAAC,CAAC;QAC/F,CAAC;QAED,OAAO,WAAW,CAAC,QAAQ,CAAC;IAC9B,CAAC;IAGK,AAAN,KAAK,CAAC,WAAW,CACO,WAAmB,EAC1B,QAA4B,EAC5B,IAA0B;QAEzC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAClE,OAAO,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,QAAQ,EAAE,QAAQ,IAAI,OAAO,CAAC,CAAC;IAC3E,CAAC;IAGK,AAAN,KAAK,CAAC,QAAQ,CACU,WAAmB,EAC1B,QAAgB,EAChB,IAA0B;QAEzC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAClE,OAAO,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC7D,CAAC;CACF,CAAA;AA5CY,oEAA4B;AA0BjC;IADL,IAAA,YAAG,EAAC,MAAM,CAAC;IAET,WAAA,IAAA,cAAK,EAAC,aAAa,CAAC,CAAA;IACpB,WAAA,IAAA,cAAK,EAAC,MAAM,CAAC,CAAA;IACb,WAAA,IAAA,oBAAW,GAAE,CAAA;;;;+DAIf;AAGK;IADL,IAAA,YAAG,EAAC,MAAM,CAAC;IAET,WAAA,IAAA,cAAK,EAAC,aAAa,CAAC,CAAA;IACpB,WAAA,IAAA,cAAK,EAAC,MAAM,CAAC,CAAA;IACb,WAAA,IAAA,oBAAW,GAAE,CAAA;;;;4DAIf;uCA3CU,4BAA4B;IAHxC,IAAA,iBAAO,EAAC,sCAAsC,CAAC;IAC/C,IAAA,iBAAQ,EAAC,IAAI,uBAAc,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9F,IAAA,mBAAU,EAAC,sCAAsC,CAAC;IAI9C,WAAA,IAAA,0BAAgB,EAAC,wBAAe,CAAC,CAAA;qCADE,4BAAY;QAEV,oBAAU;GAJvC,4BAA4B,CA4CxC"}
|
|
@@ -11,14 +11,14 @@ const common_1 = require("@nestjs/common");
|
|
|
11
11
|
const typeorm_1 = require("@nestjs/typeorm");
|
|
12
12
|
const common_2 = require("@loopstack/common");
|
|
13
13
|
const core_1 = require("@loopstack/core");
|
|
14
|
-
const
|
|
14
|
+
const remote_client_1 = require("@loopstack/remote-client");
|
|
15
15
|
const controllers_1 = require("./controllers");
|
|
16
16
|
let RemoteFileExplorerModule = class RemoteFileExplorerModule {
|
|
17
17
|
};
|
|
18
18
|
exports.RemoteFileExplorerModule = RemoteFileExplorerModule;
|
|
19
19
|
exports.RemoteFileExplorerModule = RemoteFileExplorerModule = __decorate([
|
|
20
20
|
(0, common_1.Module)({
|
|
21
|
-
imports: [core_1.LoopCoreModule,
|
|
21
|
+
imports: [core_1.LoopCoreModule, remote_client_1.RemoteClientModule, typeorm_1.TypeOrmModule.forFeature([common_2.WorkspaceEntity])],
|
|
22
22
|
controllers: [controllers_1.RemoteFileExplorerController],
|
|
23
23
|
})
|
|
24
24
|
], RemoteFileExplorerModule);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remote-file-explorer.module.js","sourceRoot":"","sources":["../src/remote-file-explorer.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,6CAAgD;AAChD,8CAAoD;AACpD,0CAAiD;AACjD,
|
|
1
|
+
{"version":3,"file":"remote-file-explorer.module.js","sourceRoot":"","sources":["../src/remote-file-explorer.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,6CAAgD;AAChD,8CAAoD;AACpD,0CAAiD;AACjD,4DAA8D;AAC9D,+CAA6D;AAMtD,IAAM,wBAAwB,GAA9B,MAAM,wBAAwB;CAAG,CAAA;AAA3B,4DAAwB;mCAAxB,wBAAwB;IAJpC,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,qBAAc,EAAE,kCAAkB,EAAE,uBAAa,CAAC,UAAU,CAAC,CAAC,wBAAe,CAAC,CAAC,CAAC;QAC1F,WAAW,EAAE,CAAC,0CAA4B,CAAC;KAC5C,CAAC;GACW,wBAAwB,CAAG"}
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"remote-agent",
|
|
9
9
|
"workflow"
|
|
10
10
|
],
|
|
11
|
-
"version": "0.22.
|
|
11
|
+
"version": "0.22.5",
|
|
12
12
|
"license": "MIT",
|
|
13
13
|
"author": {
|
|
14
14
|
"name": "Jakob Klippel",
|
|
@@ -17,8 +17,7 @@
|
|
|
17
17
|
"main": "dist/index.js",
|
|
18
18
|
"types": "dist/index.d.ts",
|
|
19
19
|
"exports": {
|
|
20
|
-
".": "./dist/index.js"
|
|
21
|
-
"./src/*": "./src/*"
|
|
20
|
+
".": "./dist/index.js"
|
|
22
21
|
},
|
|
23
22
|
"scripts": {
|
|
24
23
|
"build": "nest build",
|
|
@@ -29,16 +28,15 @@
|
|
|
29
28
|
"watch": "nest build --watch"
|
|
30
29
|
},
|
|
31
30
|
"dependencies": {
|
|
32
|
-
"@loopstack/common": "^0.
|
|
33
|
-
"@loopstack/core": "^0.
|
|
34
|
-
"@loopstack/remote-
|
|
31
|
+
"@loopstack/common": "^0.28.0",
|
|
32
|
+
"@loopstack/core": "^0.28.0",
|
|
33
|
+
"@loopstack/remote-client": "^0.23.3",
|
|
35
34
|
"@nestjs/common": "^11.1.19",
|
|
36
35
|
"@nestjs/typeorm": "^11.0.1",
|
|
37
|
-
"typeorm": "^0.3.
|
|
36
|
+
"typeorm": "^0.3.28"
|
|
38
37
|
},
|
|
39
38
|
"files": [
|
|
40
|
-
"dist"
|
|
41
|
-
"src"
|
|
39
|
+
"dist"
|
|
42
40
|
],
|
|
43
41
|
"jest": {
|
|
44
42
|
"moduleFileExtensions": [
|
|
@@ -66,7 +64,6 @@
|
|
|
66
64
|
}
|
|
67
65
|
],
|
|
68
66
|
"installModes": [
|
|
69
|
-
"add",
|
|
70
67
|
"install"
|
|
71
68
|
]
|
|
72
69
|
}
|
package/src/controllers/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './remote-file-explorer.controller';
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { Controller, Get, NotFoundException, Param, Query, UsePipes, ValidationPipe } from '@nestjs/common';
|
|
2
|
-
import { ApiTags } from '@nestjs/swagger';
|
|
3
|
-
import { InjectRepository } from '@nestjs/typeorm';
|
|
4
|
-
import { Repository } from 'typeorm';
|
|
5
|
-
import { CurrentUser, CurrentUserInterface, WorkspaceEntity } from '@loopstack/common';
|
|
6
|
-
import { RemoteAgentClient } from '@loopstack/remote-agent-client';
|
|
7
|
-
|
|
8
|
-
@ApiTags('api/v1/workspaces/:workspaceId/files')
|
|
9
|
-
@UsePipes(new ValidationPipe({ transform: true, whitelist: true, forbidNonWhitelisted: true }))
|
|
10
|
-
@Controller('api/v1/workspaces/:workspaceId/files')
|
|
11
|
-
export class RemoteFileExplorerController {
|
|
12
|
-
constructor(
|
|
13
|
-
private readonly remoteAgentClient: RemoteAgentClient,
|
|
14
|
-
@InjectRepository(WorkspaceEntity)
|
|
15
|
-
private readonly workspaceRepository: Repository<WorkspaceEntity>,
|
|
16
|
-
) {}
|
|
17
|
-
|
|
18
|
-
private async getAgentUrl(workspaceId: string, userId: string): Promise<string> {
|
|
19
|
-
const workspace = await this.workspaceRepository.findOne({
|
|
20
|
-
where: { id: workspaceId, createdBy: userId },
|
|
21
|
-
relations: ['environments'],
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
if (!workspace) {
|
|
25
|
-
throw new NotFoundException(`Workspace with ID ${workspaceId} not found`);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const environment = workspace.environments?.find((e) => !!e.agentUrl);
|
|
29
|
-
if (!environment?.agentUrl) {
|
|
30
|
-
throw new NotFoundException(`No remote environment configured for workspace ${workspaceId}`);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return environment.agentUrl;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
@Get('tree')
|
|
37
|
-
async getFileTree(
|
|
38
|
-
@Param('workspaceId') workspaceId: string,
|
|
39
|
-
@Query('path') basePath: string | undefined,
|
|
40
|
-
@CurrentUser() user: CurrentUserInterface,
|
|
41
|
-
) {
|
|
42
|
-
const agentUrl = await this.getAgentUrl(workspaceId, user.userId);
|
|
43
|
-
return this.remoteAgentClient.getFileTree(agentUrl, basePath ?? './src');
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
@Get('read')
|
|
47
|
-
async readFile(
|
|
48
|
-
@Param('workspaceId') workspaceId: string,
|
|
49
|
-
@Query('path') filePath: string,
|
|
50
|
-
@CurrentUser() user: CurrentUserInterface,
|
|
51
|
-
) {
|
|
52
|
-
const agentUrl = await this.getAgentUrl(workspaceId, user.userId);
|
|
53
|
-
return this.remoteAgentClient.readFile(agentUrl, filePath);
|
|
54
|
-
}
|
|
55
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { Module } from '@nestjs/common';
|
|
2
|
-
import { TypeOrmModule } from '@nestjs/typeorm';
|
|
3
|
-
import { WorkspaceEntity } from '@loopstack/common';
|
|
4
|
-
import { LoopCoreModule } from '@loopstack/core';
|
|
5
|
-
import { RemoteAgentClientModule } from '@loopstack/remote-agent-client';
|
|
6
|
-
import { RemoteFileExplorerController } from './controllers';
|
|
7
|
-
|
|
8
|
-
@Module({
|
|
9
|
-
imports: [LoopCoreModule, RemoteAgentClientModule, TypeOrmModule.forFeature([WorkspaceEntity])],
|
|
10
|
-
controllers: [RemoteFileExplorerController],
|
|
11
|
-
})
|
|
12
|
-
export class RemoteFileExplorerModule {}
|