crewx 0.8.8-rc.2 → 0.8.8-rc.21

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 (105) hide show
  1. package/bin/cli-commands.js +1 -1
  2. package/dist/assets/{MarketPage-Bh1UfiC2.js → MarketPage-B5JbqK4T.js} +9 -14
  3. package/dist/assets/{PromptTab-DYmYVBKo.js → PromptTab-_97mSbLk.js} +7 -7
  4. package/dist/assets/{arc-C14FbhzP.js → arc-3FDm7TxG.js} +1 -1
  5. package/dist/assets/architectureDiagram-UYN6MBPD-D8X56UlC.js +36 -0
  6. package/dist/assets/blockDiagram-ZHA2E4KO-B6jUnEVc.js +121 -0
  7. package/dist/assets/{c4Diagram-6F5ED5ID-DLSfQS-Z.js → c4Diagram-6F5ED5ID-Cy8x6Ims.js} +1 -1
  8. package/dist/assets/channel-Bs0J8jjN.js +1 -0
  9. package/dist/assets/{chunk-5HRBRIJM-j7YcJ7Bx.js → chunk-5HRBRIJM-Bh819Q5A.js} +1 -1
  10. package/dist/assets/{chunk-7U56Z5CX-Baqt1cj3.js → chunk-7U56Z5CX-CfNtPGa8.js} +1 -1
  11. package/dist/assets/{chunk-ASOPGD6M-F1YJ2mzH.js → chunk-ASOPGD6M-CMR1ElQ6.js} +1 -1
  12. package/dist/assets/{chunk-KFBOBJHC-Dvhzl6G9.js → chunk-KFBOBJHC-Dm2I1dHM.js} +1 -1
  13. package/dist/assets/{chunk-T2TOU4HS-BDczCXP6.js → chunk-T2TOU4HS-0tf-aNtk.js} +1 -1
  14. package/dist/assets/{chunk-TMUBEWPD-4BhwBH_F.js → chunk-TMUBEWPD-b5ZrpKJw.js} +1 -1
  15. package/dist/assets/classDiagram-LNE6IOMH-B1-6qC07.js +1 -0
  16. package/dist/assets/classDiagram-v2-MQ7JQ4JX-B1-6qC07.js +1 -0
  17. package/dist/assets/dagre-4EVJKHTY-zYmFBlwR.js +4 -0
  18. package/dist/assets/diagram-QW4FP2JN-DkZngH-Z.js +24 -0
  19. package/dist/assets/{erDiagram-6RL3IURR-DRhNKkH0.js → erDiagram-6RL3IURR-8TfuIQ6D.js} +2 -2
  20. package/dist/assets/{flowDiagram-7ASYPVHJ-BDJZsUJS.js → flowDiagram-7ASYPVHJ-BnhSLZTo.js} +1 -1
  21. package/dist/assets/{ganttDiagram-NTVNEXSI-BYBeyULV.js → ganttDiagram-NTVNEXSI--jDGPnYB.js} +3 -3
  22. package/dist/assets/gitGraph-YCYPL57B-DkCOt6bF.js +133 -0
  23. package/dist/assets/gitGraphDiagram-NRZ2UAAF-D4p17Lzw.js +65 -0
  24. package/dist/assets/graph-BlwPajkw.js +1 -0
  25. package/dist/assets/infoDiagram-A4XQUW5V-COnYi0Q8.js +2 -0
  26. package/dist/assets/{journeyDiagram-G5WM74LC-BhSSQ4Od.js → journeyDiagram-G5WM74LC-CTZcqDJf.js} +1 -1
  27. package/dist/assets/{kanban-definition-QRCXZQQD-CZOkitn-.js → kanban-definition-QRCXZQQD-CezLYsK3.js} +1 -1
  28. package/dist/assets/layout-Bvwu4dCi.js +1 -0
  29. package/dist/assets/{linear-BRR4YPhd.js → linear-BcYBjD0V.js} +1 -1
  30. package/dist/assets/main-CgT_Atre.js +1210 -0
  31. package/dist/assets/main-kJ_DZpZU.css +10 -0
  32. package/dist/assets/{mindmap-definition-GWI6TPTV-CiMg1rSL.js → mindmap-definition-GWI6TPTV-NM7qIPkp.js} +1 -1
  33. package/dist/assets/pieDiagram-YF2LJOPJ-Ck2UBMrZ.js +30 -0
  34. package/dist/assets/{quadrantDiagram-OS5C2QUG-cYMjsA0L.js → quadrantDiagram-OS5C2QUG-0OKnDbeW.js} +1 -1
  35. package/dist/assets/{requirementDiagram-MIRIMTAZ-D8piGWQV.js → requirementDiagram-MIRIMTAZ-Nq_mStSk.js} +2 -2
  36. package/dist/assets/{sankeyDiagram-Y46BX6SQ-DfNocUti.js → sankeyDiagram-Y46BX6SQ-ZPgHNk3C.js} +1 -1
  37. package/dist/assets/{sequenceDiagram-G6AWOVSC-Xu2X2iUX.js → sequenceDiagram-G6AWOVSC-BRzYMlx2.js} +1 -1
  38. package/dist/assets/stateDiagram-MAYHULR4-CCNAeCLE.js +1 -0
  39. package/dist/assets/stateDiagram-v2-4JROLMXI-Bz1kxCVf.js +1 -0
  40. package/dist/assets/{timeline-definition-U7ZMHBDA-CNra78s7.js → timeline-definition-U7ZMHBDA-BSw5vmnf.js} +1 -1
  41. package/dist/assets/{xychartDiagram-6QU3TZC5-BSwY5sKC.js → xychartDiagram-6QU3TZC5-BuqrahPf.js} +2 -2
  42. package/dist/index.html +2 -2
  43. package/dist-server/app.module.js +4 -0
  44. package/dist-server/bootstrap/crewx-server.js +6 -3
  45. package/dist-server/common/limits/defaults.js +2 -0
  46. package/dist-server/domain/auth/auth.module.js +2 -1
  47. package/dist-server/domain/auth/guards/base-auth.guard.js +36 -14
  48. package/dist-server/domain/doc/doc.controller.js +21 -0
  49. package/dist-server/domain/doc/doc.service.js +36 -6
  50. package/dist-server/domain/doc/image-constants.js +11 -0
  51. package/dist-server/domain/events/events.module.js +31 -0
  52. package/dist-server/domain/events/server-conversation.plugin.js +45 -0
  53. package/dist-server/domain/events/workspace-event.bus.js +32 -0
  54. package/dist-server/domain/events/workspace-event.types.js +12 -0
  55. package/dist-server/domain/events/workspace-events-test.controller.js +83 -0
  56. package/dist-server/domain/events/workspace-events.controller.js +47 -0
  57. package/dist-server/domain/mcp/browser-session.store.js +50 -0
  58. package/dist-server/domain/mcp/chromex-blacklist.js +26 -0
  59. package/dist-server/domain/mcp/chromex-negotiate.controller.js +77 -0
  60. package/dist-server/domain/mcp/chromex-negotiate.dto.js +95 -0
  61. package/dist-server/domain/mcp/chromex-negotiate.service.js +249 -0
  62. package/dist-server/domain/mcp/mcp-auth.guard.js +40 -26
  63. package/dist-server/domain/mcp/mcp.constants.js +4 -1
  64. package/dist-server/domain/mcp/mcp.controller.js +5 -4
  65. package/dist-server/domain/mcp/mcp.module.js +6 -2
  66. package/dist-server/domain/mcp/mcp.service.js +62 -5
  67. package/dist-server/domain/message/dto/send-message.dto.js +48 -1
  68. package/dist-server/domain/message/message.controller.js +40 -1
  69. package/dist-server/domain/message/message.service.js +50 -5
  70. package/dist-server/domain/task/task.service.js +34 -13
  71. package/dist-server/domain/thread/thread.controller.js +16 -0
  72. package/dist-server/domain/thread/thread.module.js +2 -0
  73. package/dist-server/domain/thread/thread.service.js +80 -11
  74. package/dist-server/domain/token/token.controller.js +73 -0
  75. package/dist-server/domain/token/token.dto.js +56 -0
  76. package/dist-server/domain/token/token.module.js +22 -0
  77. package/dist-server/domain/token/token.service.js +228 -0
  78. package/dist-server/main.js +23 -2
  79. package/dist-server/modules/crewx-pool.service.js +129 -5
  80. package/dist-server/modules/crewx.module.js +6 -0
  81. package/package.json +17 -14
  82. package/packages/cli/dist/builtin.js +2 -0
  83. package/packages/cli/dist/commands/init.js +5 -5
  84. package/packages/cli/dist/commands/registry.js +1 -1
  85. package/packages/cli/package.json +2 -1
  86. package/dist/assets/_baseUniq-B5kIqYhv.js +0 -1
  87. package/dist/assets/architectureDiagram-UYN6MBPD-Bvk4uHjQ.js +0 -36
  88. package/dist/assets/blockDiagram-ZHA2E4KO-C9-iioqe.js +0 -121
  89. package/dist/assets/channel-B1S1YSXQ.js +0 -1
  90. package/dist/assets/classDiagram-LNE6IOMH-BMiPdBl0.js +0 -1
  91. package/dist/assets/classDiagram-v2-MQ7JQ4JX-BMiPdBl0.js +0 -1
  92. package/dist/assets/clone-DkRtovKq.js +0 -1
  93. package/dist/assets/dagre-4EVJKHTY-LsgK-pqb.js +0 -4
  94. package/dist/assets/diagram-QW4FP2JN-uvhH5Eln.js +0 -24
  95. package/dist/assets/gitGraph-YCYPL57B-D9Hkzkze.js +0 -133
  96. package/dist/assets/gitGraphDiagram-NRZ2UAAF-oWiYlrjZ.js +0 -65
  97. package/dist/assets/graph-D66Q_If6.js +0 -1
  98. package/dist/assets/infoDiagram-A4XQUW5V-aJ6i9Snw.js +0 -2
  99. package/dist/assets/layout-CaxkerSC.js +0 -1
  100. package/dist/assets/main-3IYf82MG.css +0 -10
  101. package/dist/assets/main-DCHJFonK.js +0 -1167
  102. package/dist/assets/min-uKYaLZUT.js +0 -1
  103. package/dist/assets/pieDiagram-YF2LJOPJ-BFJ_DAm-.js +0 -30
  104. package/dist/assets/stateDiagram-MAYHULR4-WmJVTQsF.js +0 -1
  105. package/dist/assets/stateDiagram-v2-4JROLMXI-DNAOV6w0.js +0 -1
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.ChromexNegotiateController = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const base_auth_guard_js_1 = require("../auth/guards/base-auth.guard.js");
18
+ const chromex_negotiate_dto_js_1 = require("./chromex-negotiate.dto.js");
19
+ const chromex_negotiate_service_js_1 = require("./chromex-negotiate.service.js");
20
+ let ChromexNegotiateController = class ChromexNegotiateController {
21
+ negotiateService;
22
+ constructor(negotiateService) {
23
+ this.negotiateService = negotiateService;
24
+ }
25
+ async negotiate(dto) {
26
+ return this.negotiateService.negotiate(dto);
27
+ }
28
+ async approve(dto) {
29
+ return await this.negotiateService.approve(dto.requestId, {
30
+ expiresIn: dto.expiresIn,
31
+ scope: dto.scope,
32
+ });
33
+ }
34
+ deny(dto) {
35
+ this.negotiateService.deny(dto.requestId, dto.reason);
36
+ }
37
+ async revokeSession(dto) {
38
+ await this.negotiateService.revokeSession(dto.tokenId);
39
+ }
40
+ };
41
+ exports.ChromexNegotiateController = ChromexNegotiateController;
42
+ __decorate([
43
+ (0, common_1.Post)('negotiate'),
44
+ __param(0, (0, common_1.Body)()),
45
+ __metadata("design:type", Function),
46
+ __metadata("design:paramtypes", [chromex_negotiate_dto_js_1.NegotiateRequestDto]),
47
+ __metadata("design:returntype", Promise)
48
+ ], ChromexNegotiateController.prototype, "negotiate", null);
49
+ __decorate([
50
+ (0, common_1.Post)('approve'),
51
+ (0, common_1.HttpCode)(200),
52
+ __param(0, (0, common_1.Body)()),
53
+ __metadata("design:type", Function),
54
+ __metadata("design:paramtypes", [chromex_negotiate_dto_js_1.ApproveRequestDto]),
55
+ __metadata("design:returntype", Promise)
56
+ ], ChromexNegotiateController.prototype, "approve", null);
57
+ __decorate([
58
+ (0, common_1.Post)('deny'),
59
+ (0, common_1.HttpCode)(200),
60
+ __param(0, (0, common_1.Body)()),
61
+ __metadata("design:type", Function),
62
+ __metadata("design:paramtypes", [chromex_negotiate_dto_js_1.DenyRequestDto]),
63
+ __metadata("design:returntype", void 0)
64
+ ], ChromexNegotiateController.prototype, "deny", null);
65
+ __decorate([
66
+ (0, common_1.Delete)('session'),
67
+ (0, common_1.HttpCode)(200),
68
+ __param(0, (0, common_1.Body)()),
69
+ __metadata("design:type", Function),
70
+ __metadata("design:paramtypes", [chromex_negotiate_dto_js_1.RevokeSessionDto]),
71
+ __metadata("design:returntype", Promise)
72
+ ], ChromexNegotiateController.prototype, "revokeSession", null);
73
+ exports.ChromexNegotiateController = ChromexNegotiateController = __decorate([
74
+ (0, common_1.Controller)('api/chromex'),
75
+ (0, common_1.UseGuards)(base_auth_guard_js_1.BaseAuthGuard),
76
+ __metadata("design:paramtypes", [chromex_negotiate_service_js_1.ChromexNegotiateService])
77
+ ], ChromexNegotiateController);
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ChromexTokenResponseDto = exports.RevokeSessionDto = exports.DenyRequestDto = exports.ApproveRequestDto = exports.NegotiateRequestDto = void 0;
13
+ const class_validator_1 = require("class-validator");
14
+ class NegotiateRequestDto {
15
+ agentId;
16
+ scope;
17
+ expiresIn;
18
+ tokenName;
19
+ }
20
+ exports.NegotiateRequestDto = NegotiateRequestDto;
21
+ __decorate([
22
+ (0, class_validator_1.IsString)(),
23
+ (0, class_validator_1.MinLength)(1),
24
+ __metadata("design:type", String)
25
+ ], NegotiateRequestDto.prototype, "agentId", void 0);
26
+ __decorate([
27
+ (0, class_validator_1.IsString)(),
28
+ (0, class_validator_1.MinLength)(1),
29
+ __metadata("design:type", String)
30
+ ], NegotiateRequestDto.prototype, "scope", void 0);
31
+ __decorate([
32
+ (0, class_validator_1.IsOptional)(),
33
+ (0, class_validator_1.IsIn)(['30d', '90d', '1y']),
34
+ __metadata("design:type", String)
35
+ ], NegotiateRequestDto.prototype, "expiresIn", void 0);
36
+ __decorate([
37
+ (0, class_validator_1.IsOptional)(),
38
+ (0, class_validator_1.IsString)(),
39
+ __metadata("design:type", String)
40
+ ], NegotiateRequestDto.prototype, "tokenName", void 0);
41
+ class ApproveRequestDto {
42
+ requestId;
43
+ expiresIn;
44
+ scope;
45
+ }
46
+ exports.ApproveRequestDto = ApproveRequestDto;
47
+ __decorate([
48
+ (0, class_validator_1.IsString)(),
49
+ (0, class_validator_1.MinLength)(1),
50
+ __metadata("design:type", String)
51
+ ], ApproveRequestDto.prototype, "requestId", void 0);
52
+ __decorate([
53
+ (0, class_validator_1.IsOptional)(),
54
+ (0, class_validator_1.IsIn)(['30d', '90d', '1y']),
55
+ __metadata("design:type", String)
56
+ ], ApproveRequestDto.prototype, "expiresIn", void 0);
57
+ __decorate([
58
+ (0, class_validator_1.IsOptional)(),
59
+ (0, class_validator_1.IsString)(),
60
+ __metadata("design:type", String)
61
+ ], ApproveRequestDto.prototype, "scope", void 0);
62
+ class DenyRequestDto {
63
+ requestId;
64
+ reason;
65
+ }
66
+ exports.DenyRequestDto = DenyRequestDto;
67
+ __decorate([
68
+ (0, class_validator_1.IsString)(),
69
+ (0, class_validator_1.MinLength)(1),
70
+ __metadata("design:type", String)
71
+ ], DenyRequestDto.prototype, "requestId", void 0);
72
+ __decorate([
73
+ (0, class_validator_1.IsOptional)(),
74
+ (0, class_validator_1.IsString)(),
75
+ __metadata("design:type", String)
76
+ ], DenyRequestDto.prototype, "reason", void 0);
77
+ class RevokeSessionDto {
78
+ tokenId;
79
+ }
80
+ exports.RevokeSessionDto = RevokeSessionDto;
81
+ __decorate([
82
+ (0, class_validator_1.IsString)(),
83
+ (0, class_validator_1.MinLength)(1),
84
+ __metadata("design:type", String)
85
+ ], RevokeSessionDto.prototype, "tokenId", void 0);
86
+ class ChromexTokenResponseDto {
87
+ token; // crewx_<JWT> — Bearer로 사용
88
+ tokenId; // tok_... (revoke용)
89
+ jti; // JWT ID
90
+ expiresAt; // ISO 8601
91
+ scope;
92
+ agentId;
93
+ mcpSessionId;
94
+ }
95
+ exports.ChromexTokenResponseDto = ChromexTokenResponseDto;
@@ -0,0 +1,249 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ChromexNegotiateService = void 0;
13
+ const common_1 = require("@nestjs/common");
14
+ const path_1 = require("path");
15
+ const os_1 = require("os");
16
+ const nanoid_1 = require("nanoid");
17
+ const token_service_js_1 = require("../token/token.service.js");
18
+ const browser_session_store_js_1 = require("./browser-session.store.js");
19
+ const mcp_constants_js_1 = require("./mcp.constants.js");
20
+ const NEGOTIATE_TIMEOUT_MS = 60_000;
21
+ const PROCESSED_TTL_MS = 5 * 60_000;
22
+ let ChromexNegotiateService = class ChromexNegotiateService {
23
+ tokenService;
24
+ browserSessions;
25
+ pendingRequests = new Map();
26
+ pendingAgentIds = new Set();
27
+ processedRequests = new Set();
28
+ db;
29
+ constructor(tokenService, browserSessions) {
30
+ this.tokenService = tokenService;
31
+ this.browserSessions = browserSessions;
32
+ }
33
+ onModuleInit() {
34
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
35
+ const Database = require('better-sqlite3');
36
+ const dbPath = process.env.CREWX_DB ?? (0, path_1.join)((0, os_1.homedir)(), '.crewx', 'crewx.db');
37
+ this.db = new Database(dbPath);
38
+ this.db.exec('PRAGMA journal_mode = WAL');
39
+ this.db.exec('PRAGMA busy_timeout = 5000');
40
+ this.db.exec(`
41
+ CREATE TABLE IF NOT EXISTS chromex_audit_log (
42
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
43
+ timestamp TEXT NOT NULL DEFAULT (datetime('now')),
44
+ agent_id TEXT NOT NULL,
45
+ action TEXT NOT NULL,
46
+ jti TEXT,
47
+ scope TEXT,
48
+ tab_url TEXT,
49
+ tool_name TEXT,
50
+ result TEXT,
51
+ detail TEXT
52
+ )
53
+ `);
54
+ }
55
+ onModuleDestroy() {
56
+ try {
57
+ this.db?.close();
58
+ }
59
+ catch {
60
+ // ignore close errors during shutdown
61
+ }
62
+ }
63
+ async negotiate(dto) {
64
+ if (this.pendingAgentIds.has(dto.agentId)) {
65
+ throw new common_1.ConflictException('Negotiate already pending for this agent');
66
+ }
67
+ const browserSession = this.browserSessions.getLatestBrowserSession();
68
+ if (!browserSession) {
69
+ throw new common_1.HttpException({ reason: 'no_browser_connected' }, 503);
70
+ }
71
+ const requestId = 'req_' + (0, nanoid_1.nanoid)(21);
72
+ const expiresIn = dto.expiresIn ?? '90d';
73
+ const negotiateExpiresAt = new Date(Date.now() + NEGOTIATE_TIMEOUT_MS).toISOString();
74
+ const tokenName = dto.tokenName ?? `${dto.agentId}-${new Date().toISOString().slice(0, 7)}`;
75
+ const payload = {
76
+ jsonrpc: '2.0',
77
+ method: mcp_constants_js_1.CHROMEX_EVENTS.NEGOTIATE_REQUEST,
78
+ params: {
79
+ requestId,
80
+ agentId: dto.agentId,
81
+ scope: dto.scope,
82
+ expiresIn,
83
+ mcpSessionId: browserSession.id,
84
+ tokenName,
85
+ negotiateExpiresAt,
86
+ },
87
+ };
88
+ this.pendingAgentIds.add(dto.agentId);
89
+ // log when the negotiate request is registered
90
+ this.auditLog({
91
+ agentId: dto.agentId,
92
+ action: 'negotiate',
93
+ scope: dto.scope,
94
+ result: 'success',
95
+ }).catch(() => { });
96
+ return new Promise((resolvePromise, rejectPromise) => {
97
+ let unregisterDisconnect = () => { };
98
+ const resolve = (value) => {
99
+ clearTimeout(timeout);
100
+ unregisterDisconnect();
101
+ resolvePromise(value);
102
+ };
103
+ const reject = (reason) => {
104
+ clearTimeout(timeout);
105
+ unregisterDisconnect();
106
+ rejectPromise(reason);
107
+ };
108
+ const timeout = setTimeout(() => {
109
+ if (this.pendingRequests.has(requestId)) {
110
+ const entry = this.pendingRequests.get(requestId);
111
+ this.pendingRequests.delete(requestId);
112
+ this.pendingAgentIds.delete(dto.agentId);
113
+ this.processedRequests.add(requestId);
114
+ this.scheduleProcessedCleanup(requestId);
115
+ this.auditLog({
116
+ agentId: dto.agentId,
117
+ action: 'timeout',
118
+ scope: entry.scope,
119
+ result: 'timeout',
120
+ }).catch(() => { });
121
+ reject(new common_1.HttpException({ reason: 'timeout' }, 408));
122
+ }
123
+ }, NEGOTIATE_TIMEOUT_MS);
124
+ this.pendingRequests.set(requestId, {
125
+ agentId: dto.agentId,
126
+ scope: dto.scope,
127
+ expiresIn,
128
+ mcpSessionId: browserSession.id,
129
+ tokenName: dto.tokenName,
130
+ resolve,
131
+ reject,
132
+ timeout,
133
+ });
134
+ unregisterDisconnect = this.browserSessions.onSseDisconnect(browserSession.id, () => {
135
+ if (this.pendingRequests.has(requestId)) {
136
+ this.pendingRequests.delete(requestId);
137
+ this.pendingAgentIds.delete(dto.agentId);
138
+ this.processedRequests.add(requestId);
139
+ this.scheduleProcessedCleanup(requestId);
140
+ reject(new common_1.HttpException({ reason: 'no_browser_connected' }, 503));
141
+ }
142
+ });
143
+ const pushed = this.browserSessions.pushNotification(browserSession.id, payload);
144
+ if (!pushed) {
145
+ this.pendingRequests.delete(requestId);
146
+ this.pendingAgentIds.delete(dto.agentId);
147
+ this.processedRequests.add(requestId);
148
+ this.scheduleProcessedCleanup(requestId);
149
+ reject(new common_1.HttpException({ reason: 'no_browser_connected' }, 503));
150
+ }
151
+ });
152
+ }
153
+ async approve(requestId, overrides) {
154
+ if (this.processedRequests.has(requestId))
155
+ return undefined;
156
+ const entry = this.pendingRequests.get(requestId);
157
+ if (!entry)
158
+ throw new common_1.NotFoundException('Negotiate request not found');
159
+ this.pendingRequests.delete(requestId);
160
+ this.pendingAgentIds.delete(entry.agentId);
161
+ this.processedRequests.add(requestId);
162
+ this.scheduleProcessedCleanup(requestId);
163
+ clearTimeout(entry.timeout);
164
+ try {
165
+ const expiresIn = overrides?.expiresIn ?? entry.expiresIn;
166
+ const scope = overrides?.scope ?? entry.scope;
167
+ const { token, meta } = await this.tokenService.createToken({
168
+ name: entry.tokenName ?? `${entry.agentId}-${new Date().toISOString().slice(0, 10)}`,
169
+ expiresIn,
170
+ agentScope: entry.agentId,
171
+ browserScope: scope,
172
+ }, 'negotiate');
173
+ this.auditLog({
174
+ agentId: entry.agentId,
175
+ action: 'approve',
176
+ jti: meta.jti,
177
+ scope,
178
+ result: 'success',
179
+ }).catch(() => { });
180
+ const response = {
181
+ token,
182
+ tokenId: meta.id,
183
+ jti: meta.jti,
184
+ expiresAt: meta.expiresAt,
185
+ scope,
186
+ agentId: entry.agentId,
187
+ mcpSessionId: entry.mcpSessionId,
188
+ };
189
+ entry.resolve(response);
190
+ return response;
191
+ }
192
+ catch (err) {
193
+ entry.reject(err);
194
+ throw err;
195
+ }
196
+ }
197
+ deny(requestId, reason = 'user_denied') {
198
+ if (this.processedRequests.has(requestId))
199
+ return;
200
+ const entry = this.pendingRequests.get(requestId);
201
+ if (!entry)
202
+ throw new common_1.NotFoundException('Negotiate request not found');
203
+ this.pendingRequests.delete(requestId);
204
+ this.pendingAgentIds.delete(entry.agentId);
205
+ this.processedRequests.add(requestId);
206
+ this.scheduleProcessedCleanup(requestId);
207
+ clearTimeout(entry.timeout);
208
+ this.auditLog({
209
+ agentId: entry.agentId,
210
+ action: 'deny',
211
+ scope: entry.scope,
212
+ result: 'denied',
213
+ detail: { reason },
214
+ }).catch(() => { });
215
+ entry.reject(new common_1.HttpException({ reason }, 403));
216
+ }
217
+ async revokeSession(tokenId) {
218
+ await this.tokenService.revokeToken(tokenId);
219
+ }
220
+ getPendingRequests() {
221
+ return Array.from(this.pendingRequests.entries()).map(([requestId, entry]) => ({
222
+ requestId,
223
+ agentId: entry.agentId,
224
+ scope: entry.scope,
225
+ expiresIn: entry.expiresIn,
226
+ tokenName: entry.tokenName,
227
+ }));
228
+ }
229
+ logAudit(params) {
230
+ void this.auditLog(params);
231
+ }
232
+ async auditLog(params) {
233
+ if (!this.db)
234
+ return;
235
+ this.db
236
+ .prepare(`INSERT INTO chromex_audit_log (agent_id, action, jti, scope, tab_url, tool_name, result, detail)
237
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
238
+ .run(params.agentId, params.action, params.jti ?? null, params.scope ?? null, params.tabUrl ?? null, params.toolName ?? null, params.result, params.detail ? JSON.stringify(params.detail) : null);
239
+ }
240
+ scheduleProcessedCleanup(requestId) {
241
+ setTimeout(() => this.processedRequests.delete(requestId), PROCESSED_TTL_MS);
242
+ }
243
+ };
244
+ exports.ChromexNegotiateService = ChromexNegotiateService;
245
+ exports.ChromexNegotiateService = ChromexNegotiateService = __decorate([
246
+ (0, common_1.Injectable)(),
247
+ __metadata("design:paramtypes", [token_service_js_1.TokenService,
248
+ browser_session_store_js_1.BrowserSessionStore])
249
+ ], ChromexNegotiateService);
@@ -14,41 +14,54 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.McpAuthGuard = void 0;
16
16
  const common_1 = require("@nestjs/common");
17
+ const token_service_js_1 = require("../token/token.service.js");
17
18
  const mcp_constants_js_1 = require("./mcp.constants.js");
19
+ const ip_utils_js_1 = require("../auth/utils/ip.utils.js");
18
20
  let McpAuthGuard = class McpAuthGuard {
21
+ tokenService;
19
22
  tokenInfo;
20
- constructor(tokenInfo) {
23
+ constructor(tokenService, tokenInfo) {
24
+ this.tokenService = tokenService;
21
25
  this.tokenInfo = tokenInfo;
22
26
  }
23
- canActivate(context) {
27
+ async canActivate(context) {
24
28
  const request = context.switchToHttp().getRequest();
25
- // Extract token: Authorization header takes priority over query parameter
26
- const bearerToken = this.extractTokenFromHeader(request)
27
- ?? this.extractTokenFromQuery(request);
28
- if (!bearerToken) {
29
- throw new common_1.UnauthorizedException('Missing authentication token');
29
+ const rawToken = this.extractToken(request);
30
+ if (rawToken) {
31
+ // DB JWT token validation
32
+ const claims = await this.tokenService.validateToken(rawToken);
33
+ if (claims) {
34
+ request.tokenClaims = claims;
35
+ return true;
36
+ }
37
+ // Legacy fallback: existing Chrome X installs may still store the generated
38
+ // MCP bearer token from server startup instead of a DB-backed crewx_ token.
39
+ if (rawToken === this.tokenInfo.token)
40
+ return true;
30
41
  }
31
- if (bearerToken !== this.tokenInfo.token) {
32
- throw new common_1.UnauthorizedException('Invalid bearer token');
42
+ if (this.isLocalRequest(request))
43
+ return true;
44
+ if (!rawToken) {
45
+ throw new common_1.UnauthorizedException('Bearer token required');
33
46
  }
34
- return true;
47
+ throw new common_1.UnauthorizedException('Invalid token');
35
48
  }
36
- extractTokenFromHeader(request) {
49
+ isLocalRequest(request) {
50
+ const ip = request.socket?.remoteAddress;
51
+ if (!(0, ip_utils_js_1.isLoopback)(ip))
52
+ return false;
53
+ const host = (request.headers['host'] ?? '').split(':')[0];
54
+ return host === 'localhost' || host === '127.0.0.1' || host === '[::1]';
55
+ }
56
+ extractToken(request) {
37
57
  const authHeader = request.headers['authorization'] || request.headers['Authorization'];
38
- if (!authHeader || typeof authHeader !== 'string') {
39
- return null;
40
- }
41
- const prefix = 'Bearer ';
42
- if (!authHeader.startsWith(prefix)) {
43
- return null;
58
+ if (typeof authHeader === 'string' && authHeader.startsWith('Bearer ')) {
59
+ const token = authHeader.slice(7).trim();
60
+ return token || null;
44
61
  }
45
- const token = authHeader.slice(prefix.length).trim();
46
- return token || null;
47
- }
48
- extractTokenFromQuery(request) {
49
- const token = request.query['token'];
50
- if (typeof token === 'string' && token.length > 0) {
51
- return token;
62
+ const queryToken = request.query['token'];
63
+ if (typeof queryToken === 'string' && queryToken.length > 0) {
64
+ return queryToken;
52
65
  }
53
66
  return null;
54
67
  }
@@ -56,6 +69,7 @@ let McpAuthGuard = class McpAuthGuard {
56
69
  exports.McpAuthGuard = McpAuthGuard;
57
70
  exports.McpAuthGuard = McpAuthGuard = __decorate([
58
71
  (0, common_1.Injectable)(),
59
- __param(0, (0, common_1.Inject)(mcp_constants_js_1.MCP_TOKEN)),
60
- __metadata("design:paramtypes", [Object])
72
+ __param(0, (0, common_1.Inject)(token_service_js_1.TokenService)),
73
+ __param(1, (0, common_1.Inject)(mcp_constants_js_1.MCP_TOKEN)),
74
+ __metadata("design:paramtypes", [token_service_js_1.TokenService, Object])
61
75
  ], McpAuthGuard);
@@ -1,4 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MCP_TOKEN = void 0;
3
+ exports.CHROMEX_EVENTS = exports.MCP_TOKEN = void 0;
4
4
  exports.MCP_TOKEN = 'MCP_TOKEN';
5
+ exports.CHROMEX_EVENTS = {
6
+ NEGOTIATE_REQUEST: 'chromex/negotiate',
7
+ };
@@ -25,7 +25,7 @@ let McpController = McpController_1 = class McpController {
25
25
  constructor(mcpService) {
26
26
  this.mcpService = mcpService;
27
27
  }
28
- async handleMcp(body, sessionId, clientType, res) {
28
+ async handleMcp(body, sessionId, clientType, req, res) {
29
29
  this.logger.debug(`MCP request [session=${sessionId ?? 'none'}]: ${JSON.stringify(body)}`);
30
30
  // JSON-RPC response from extension (has result or error, no method)
31
31
  // Must be checked BEFORE validateRequest — responses have no method field
@@ -45,7 +45,7 @@ let McpController = McpController_1 = class McpController {
45
45
  res.status(200).json(validationError);
46
46
  return;
47
47
  }
48
- const result = await this.mcpService.handleRequest(body, sessionId, clientType);
48
+ const result = await this.mcpService.handleRequest(body, sessionId, clientType, req);
49
49
  // Notifications return null
50
50
  if (result === null) {
51
51
  this.logger.debug(`Notification processed: ${body.method}`);
@@ -97,9 +97,10 @@ __decorate([
97
97
  __param(0, (0, common_1.Body)()),
98
98
  __param(1, (0, common_1.Headers)(MCP_SESSION_HEADER)),
99
99
  __param(2, (0, common_1.Headers)('x-client-type')),
100
- __param(3, (0, common_1.Res)()),
100
+ __param(3, (0, common_1.Req)()),
101
+ __param(4, (0, common_1.Res)()),
101
102
  __metadata("design:type", Function),
102
- __metadata("design:paramtypes", [Object, Object, Object, Object]),
103
+ __metadata("design:paramtypes", [Object, Object, Object, Object, Object]),
103
104
  __metadata("design:returntype", Promise)
104
105
  ], McpController.prototype, "handleMcp", null);
105
106
  __decorate([
@@ -17,15 +17,19 @@ const tool_router_service_js_1 = require("./tool-router.service.js");
17
17
  const mcp_constants_js_1 = require("./mcp.constants.js");
18
18
  const crewx_module_js_1 = require("../../modules/crewx.module.js");
19
19
  const repository_1 = require("@crewx/sdk/repository");
20
+ const token_module_js_1 = require("../token/token.module.js");
21
+ const chromex_negotiate_controller_js_1 = require("./chromex-negotiate.controller.js");
22
+ const chromex_negotiate_service_js_1 = require("./chromex-negotiate.service.js");
20
23
  let McpModule = class McpModule {
21
24
  };
22
25
  exports.McpModule = McpModule;
23
26
  exports.McpModule = McpModule = __decorate([
24
27
  (0, common_1.Module)({
25
- imports: [crewx_module_js_1.CrewxModule],
26
- controllers: [mcp_controller_js_1.McpController],
28
+ imports: [crewx_module_js_1.CrewxModule, token_module_js_1.TokenModule],
29
+ controllers: [mcp_controller_js_1.McpController, chromex_negotiate_controller_js_1.ChromexNegotiateController],
27
30
  providers: [
28
31
  mcp_service_js_1.McpService,
32
+ chromex_negotiate_service_js_1.ChromexNegotiateService,
29
33
  browser_session_store_js_1.BrowserSessionStore,
30
34
  tool_router_service_js_1.ToolRouterService,
31
35
  {