hoolix 0.0.1 → 0.0.3

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 (67) hide show
  1. package/README.md +31 -1
  2. package/dist/commands/approvals.d.ts +2 -0
  3. package/dist/commands/approvals.d.ts.map +1 -0
  4. package/dist/commands/approvals.js +65 -0
  5. package/dist/commands/approvals.js.map +1 -0
  6. package/dist/commands/completion.d.ts.map +1 -1
  7. package/dist/commands/completion.js +123 -2
  8. package/dist/commands/completion.js.map +1 -1
  9. package/dist/commands/connect.d.ts.map +1 -1
  10. package/dist/commands/connect.js +8 -0
  11. package/dist/commands/connect.js.map +1 -1
  12. package/dist/commands/doctor.d.ts.map +1 -1
  13. package/dist/commands/doctor.js +44 -1
  14. package/dist/commands/doctor.js.map +1 -1
  15. package/dist/commands/gateway.d.ts +2 -0
  16. package/dist/commands/gateway.d.ts.map +1 -0
  17. package/dist/commands/gateway.js +237 -0
  18. package/dist/commands/gateway.js.map +1 -0
  19. package/dist/commands/list.d.ts.map +1 -1
  20. package/dist/commands/list.js +22 -3
  21. package/dist/commands/list.js.map +1 -1
  22. package/dist/commands/profile.d.ts +2 -0
  23. package/dist/commands/profile.d.ts.map +1 -0
  24. package/dist/commands/profile.js +169 -0
  25. package/dist/commands/profile.js.map +1 -0
  26. package/dist/core/approvals.d.ts +67 -0
  27. package/dist/core/approvals.d.ts.map +1 -0
  28. package/dist/core/approvals.js +104 -0
  29. package/dist/core/approvals.js.map +1 -0
  30. package/dist/core/gateways.d.ts +62 -0
  31. package/dist/core/gateways.d.ts.map +1 -0
  32. package/dist/core/gateways.js +115 -0
  33. package/dist/core/gateways.js.map +1 -0
  34. package/dist/core/paths.d.ts +9 -0
  35. package/dist/core/paths.d.ts.map +1 -1
  36. package/dist/core/paths.js +27 -0
  37. package/dist/core/paths.js.map +1 -1
  38. package/dist/core/policy.d.ts +20 -0
  39. package/dist/core/policy.d.ts.map +1 -0
  40. package/dist/core/policy.js +95 -0
  41. package/dist/core/policy.js.map +1 -0
  42. package/dist/core/profiles.d.ts +141 -0
  43. package/dist/core/profiles.d.ts.map +1 -0
  44. package/dist/core/profiles.js +159 -0
  45. package/dist/core/profiles.js.map +1 -0
  46. package/dist/core/version.d.ts +1 -1
  47. package/dist/core/version.js +1 -1
  48. package/dist/index.js +38 -1
  49. package/dist/index.js.map +1 -1
  50. package/dist/mcp/gateway-host.d.ts +8 -0
  51. package/dist/mcp/gateway-host.d.ts.map +1 -0
  52. package/dist/mcp/gateway-host.js +447 -0
  53. package/dist/mcp/gateway-host.js.map +1 -0
  54. package/dist/mcp/proxy-host.d.ts.map +1 -1
  55. package/dist/mcp/proxy-host.js +3 -2
  56. package/dist/mcp/proxy-host.js.map +1 -1
  57. package/dist/process/manager.d.ts +17 -1
  58. package/dist/process/manager.d.ts.map +1 -1
  59. package/dist/process/manager.js +105 -1
  60. package/dist/process/manager.js.map +1 -1
  61. package/dist/tui/index.d.ts.map +1 -1
  62. package/dist/tui/index.js +223 -32
  63. package/dist/tui/index.js.map +1 -1
  64. package/dist/ui/help.d.ts.map +1 -1
  65. package/dist/ui/help.js +10 -0
  66. package/dist/ui/help.js.map +1 -1
  67. package/package.json +1 -1
@@ -0,0 +1,104 @@
1
+ import { z } from 'zod';
2
+ import fs from 'fs-extra';
3
+ import { getApprovalsPath, ensureDirectories } from './paths.js';
4
+ export const ApprovalStatusSchema = z.enum(['pending', 'approved', 'denied', 'consumed']);
5
+ export const ApprovalRecordSchema = z.object({
6
+ id: z.string(),
7
+ status: ApprovalStatusSchema,
8
+ gateway: z.string(),
9
+ profile: z.string(),
10
+ toolName: z.string(),
11
+ backend: z.string().optional(),
12
+ argumentsPreview: z.string(),
13
+ argumentsHash: z.string(),
14
+ createdAt: z.string().datetime(),
15
+ decidedAt: z.string().datetime().optional(),
16
+ });
17
+ async function loadStore() {
18
+ await ensureDirectories();
19
+ const path = getApprovalsPath();
20
+ if (!(await fs.pathExists(path))) {
21
+ const fresh = { version: '1.0.0', approvals: [] };
22
+ await fs.writeJson(path, fresh, { spaces: 2 });
23
+ return fresh;
24
+ }
25
+ const raw = await fs.readJson(path);
26
+ const approvals = z.array(ApprovalRecordSchema).parse(raw.approvals ?? []);
27
+ return { version: String(raw.version ?? '1.0.0'), approvals };
28
+ }
29
+ async function saveStore(store) {
30
+ await fs.writeJson(getApprovalsPath(), store, { spaces: 2 });
31
+ }
32
+ export async function listApprovals(status) {
33
+ const store = await loadStore();
34
+ const approvals = status ? store.approvals.filter((approval) => approval.status === status) : store.approvals;
35
+ return approvals.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
36
+ }
37
+ export async function listPendingApprovals() {
38
+ return listApprovals('pending');
39
+ }
40
+ export async function queueApproval(input) {
41
+ const store = await loadStore();
42
+ const existing = store.approvals.find((approval) => approval.status === 'pending' &&
43
+ approval.gateway === input.gateway &&
44
+ approval.profile === input.profile &&
45
+ approval.toolName === input.toolName &&
46
+ approval.argumentsHash === input.argumentsHash);
47
+ if (existing)
48
+ return existing;
49
+ const record = {
50
+ id: `appr_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`,
51
+ status: 'pending',
52
+ gateway: input.gateway,
53
+ profile: input.profile,
54
+ toolName: input.toolName,
55
+ backend: input.backend,
56
+ argumentsPreview: input.argumentsPreview,
57
+ argumentsHash: input.argumentsHash,
58
+ createdAt: new Date().toISOString(),
59
+ };
60
+ store.approvals.push(record);
61
+ await saveStore(store);
62
+ return record;
63
+ }
64
+ export async function decideApproval(id, status) {
65
+ const store = await loadStore();
66
+ const record = store.approvals.find((approval) => approval.id === id);
67
+ if (!record)
68
+ throw new Error(`Approval "${id}" not found. Next: run hoolix approvals list.`);
69
+ record.status = status;
70
+ record.decidedAt = new Date().toISOString();
71
+ await saveStore(store);
72
+ return record;
73
+ }
74
+ export async function consumeMatchingApproval(input) {
75
+ const store = await loadStore();
76
+ const record = store.approvals.find((approval) => approval.status === 'approved' &&
77
+ approval.gateway === input.gateway &&
78
+ approval.profile === input.profile &&
79
+ approval.toolName === input.toolName &&
80
+ approval.argumentsHash === input.argumentsHash);
81
+ if (!record)
82
+ return null;
83
+ record.status = 'consumed';
84
+ record.decidedAt = new Date().toISOString();
85
+ await saveStore(store);
86
+ return record;
87
+ }
88
+ export async function findDeniedMatchingApproval(input) {
89
+ const store = await loadStore();
90
+ return store.approvals.find((approval) => approval.status === 'denied' &&
91
+ approval.gateway === input.gateway &&
92
+ approval.profile === input.profile &&
93
+ approval.toolName === input.toolName &&
94
+ approval.argumentsHash === input.argumentsHash) ?? null;
95
+ }
96
+ export function previewArgs(value) {
97
+ const json = JSON.stringify(value ?? {});
98
+ return json.length > 500 ? `${json.slice(0, 500)}...` : json;
99
+ }
100
+ export async function hashArgs(value) {
101
+ const crypto = await import('node:crypto');
102
+ return crypto.createHash('sha256').update(JSON.stringify(value ?? {})).digest('hex');
103
+ }
104
+ //# sourceMappingURL=approvals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approvals.js","sourceRoot":"","sources":["../../src/core/approvals.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEjE,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;AAE1F,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE;IACd,MAAM,EAAE,oBAAoB;IAC5B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE;IAC5B,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE;IACzB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;CAC5C,CAAC,CAAC;AASH,KAAK,UAAU,SAAS;IACtB,MAAM,iBAAiB,EAAE,CAAC;IAC1B,MAAM,IAAI,GAAG,gBAAgB,EAAE,CAAC;IAChC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QACjC,MAAM,KAAK,GAAkB,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;QACjE,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QAC/C,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;IAC3E,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC,EAAE,SAAS,EAAE,CAAC;AAChE,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,KAAoB;IAC3C,MAAM,EAAE,CAAC,SAAS,CAAC,gBAAgB,EAAE,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAiC;IACnE,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAC;IAChC,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;IAC9G,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AAC1E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB;IACxC,OAAO,aAAa,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAOnC;IACC,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAC;IAChC,MAAM,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CACjD,QAAQ,CAAC,MAAM,KAAK,SAAS;QAC7B,QAAQ,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO;QAClC,QAAQ,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO;QAClC,QAAQ,CAAC,QAAQ,KAAK,KAAK,CAAC,QAAQ;QACpC,QAAQ,CAAC,aAAa,KAAK,KAAK,CAAC,aAAa,CAC/C,CAAC;IACF,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,MAAM,MAAM,GAAmB;QAC7B,EAAE,EAAE,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;QAC/E,MAAM,EAAE,SAAS;QACjB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;QACxC,aAAa,EAAE,KAAK,CAAC,aAAa;QAClC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IACF,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7B,MAAM,SAAS,CAAC,KAAK,CAAC,CAAC;IACvB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,EAAU,EAAE,MAA6B;IAC5E,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAC;IAChC,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACtE,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,aAAa,EAAE,+CAA+C,CAAC,CAAC;IAC7F,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,MAAM,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC5C,MAAM,SAAS,CAAC,KAAK,CAAC,CAAC;IACvB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,KAK7C;IACC,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAC;IAChC,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAC/C,QAAQ,CAAC,MAAM,KAAK,UAAU;QAC9B,QAAQ,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO;QAClC,QAAQ,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO;QAClC,QAAQ,CAAC,QAAQ,KAAK,KAAK,CAAC,QAAQ;QACpC,QAAQ,CAAC,aAAa,KAAK,KAAK,CAAC,aAAa,CAC/C,CAAC;IACF,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,CAAC,MAAM,GAAG,UAAU,CAAC;IAC3B,MAAM,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC5C,MAAM,SAAS,CAAC,KAAK,CAAC,CAAC;IACvB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAC,KAKhD;IACC,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAC;IAChC,OAAO,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CACvC,QAAQ,CAAC,MAAM,KAAK,QAAQ;QAC5B,QAAQ,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO;QAClC,QAAQ,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO;QAClC,QAAQ,CAAC,QAAQ,KAAK,KAAK,CAAC,QAAQ;QACpC,QAAQ,CAAC,aAAa,KAAK,KAAK,CAAC,aAAa,CAC/C,IAAI,IAAI,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IACzC,OAAO,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,KAAc;IAC3C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IAC3C,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACvF,CAAC"}
@@ -0,0 +1,62 @@
1
+ import { z } from 'zod';
2
+ export declare const GatewayBackingSchema: z.ZodObject<{
3
+ slug: z.ZodString;
4
+ namespace: z.ZodString;
5
+ templateId: z.ZodOptional<z.ZodString>;
6
+ }, "strip", z.ZodTypeAny, {
7
+ slug: string;
8
+ namespace: string;
9
+ templateId?: string | undefined;
10
+ }, {
11
+ slug: string;
12
+ namespace: string;
13
+ templateId?: string | undefined;
14
+ }>;
15
+ export declare const GatewayConfigSchema: z.ZodObject<{
16
+ name: z.ZodString;
17
+ slug: z.ZodString;
18
+ authKey: z.ZodString;
19
+ backends: z.ZodArray<z.ZodObject<{
20
+ slug: z.ZodString;
21
+ namespace: z.ZodString;
22
+ templateId: z.ZodOptional<z.ZodString>;
23
+ }, "strip", z.ZodTypeAny, {
24
+ slug: string;
25
+ namespace: string;
26
+ templateId?: string | undefined;
27
+ }, {
28
+ slug: string;
29
+ namespace: string;
30
+ templateId?: string | undefined;
31
+ }>, "many">;
32
+ createdAt: z.ZodString;
33
+ lastUpdatedAt: z.ZodString;
34
+ }, "strip", z.ZodTypeAny, {
35
+ name: string;
36
+ slug: string;
37
+ createdAt: string;
38
+ lastUpdatedAt: string;
39
+ authKey: string;
40
+ backends: {
41
+ slug: string;
42
+ namespace: string;
43
+ templateId?: string | undefined;
44
+ }[];
45
+ }, {
46
+ name: string;
47
+ slug: string;
48
+ createdAt: string;
49
+ lastUpdatedAt: string;
50
+ authKey: string;
51
+ backends: {
52
+ slug: string;
53
+ namespace: string;
54
+ templateId?: string | undefined;
55
+ }[];
56
+ }>;
57
+ export type GatewayBacking = z.infer<typeof GatewayBackingSchema>;
58
+ export type GatewayConfig = z.infer<typeof GatewayConfigSchema>;
59
+ export declare function createGateway(name: string, includes: string[]): Promise<GatewayConfig>;
60
+ export declare function listGateways(): Promise<GatewayConfig[]>;
61
+ export declare function getGateway(slug: string): Promise<GatewayConfig>;
62
+ //# sourceMappingURL=gateways.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateways.d.ts","sourceRoot":"","sources":["../../src/core/gateways.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAaxB,eAAO,MAAM,oBAAoB;;;;;;;;;;;;EAI/B,CAAC;AAEH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAO9B,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAkDhE,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAwC5F;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAW7D;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAMrE"}
@@ -0,0 +1,115 @@
1
+ import { z } from 'zod';
2
+ import fs from 'fs-extra';
3
+ import path from 'node:path';
4
+ import { ensureDirectories, getGatewayConfigPath, getGatewayDataDir, getGatewayDir, getPaths, } from './paths.js';
5
+ import { generateAuthKey } from '../lib/auth.js';
6
+ import { getServerMetadata, slugify } from './registry.js';
7
+ export const GatewayBackingSchema = z.object({
8
+ slug: z.string().regex(/^[a-z0-9-]{1,64}$/),
9
+ namespace: z.string().regex(/^[a-z0-9][a-z0-9-]{0,63}$/),
10
+ templateId: z.string().optional(),
11
+ });
12
+ export const GatewayConfigSchema = z.object({
13
+ name: z.string(),
14
+ slug: z.string().regex(/^[a-z0-9-]{1,64}$/),
15
+ authKey: z.string().min(16),
16
+ backends: z.array(GatewayBackingSchema).min(1),
17
+ createdAt: z.string().datetime(),
18
+ lastUpdatedAt: z.string().datetime(),
19
+ });
20
+ const GATEWAY_INDEX_FILE = 'gateways.json';
21
+ function gatewayIndexPath() {
22
+ return path.join(getPaths().data, GATEWAY_INDEX_FILE);
23
+ }
24
+ async function loadGatewayIndex() {
25
+ await ensureDirectories();
26
+ const indexPath = gatewayIndexPath();
27
+ if (!(await fs.pathExists(indexPath))) {
28
+ const fresh = { version: '1.0.0', gateways: {} };
29
+ await fs.writeJson(indexPath, fresh, { spaces: 2 });
30
+ return fresh;
31
+ }
32
+ return fs.readJson(indexPath);
33
+ }
34
+ async function saveGatewayIndex(index) {
35
+ await fs.writeJson(gatewayIndexPath(), index, { spaces: 2 });
36
+ }
37
+ function namespaceFromTemplate(templateId, slug) {
38
+ const base = templateId || slug;
39
+ return slugify(base.replace(/-api$/, '').replace(/-search$/, ''));
40
+ }
41
+ function dedupeNamespace(namespace, seen, fallback) {
42
+ if (!seen.has(namespace)) {
43
+ seen.add(namespace);
44
+ return namespace;
45
+ }
46
+ const bySlug = slugify(fallback);
47
+ if (!seen.has(bySlug)) {
48
+ seen.add(bySlug);
49
+ return bySlug;
50
+ }
51
+ let i = 2;
52
+ while (seen.has(`${bySlug}-${i}`))
53
+ i++;
54
+ const next = `${bySlug}-${i}`;
55
+ seen.add(next);
56
+ return next;
57
+ }
58
+ export async function createGateway(name, includes) {
59
+ const slug = slugify(name);
60
+ const uniqueIncludes = [...new Set(includes.map((include) => slugify(include)).filter(Boolean))];
61
+ if (uniqueIncludes.length === 0) {
62
+ throw new Error('Gateway needs at least one --include <server-slug>. Next: run hoolix list.');
63
+ }
64
+ const index = await loadGatewayIndex();
65
+ if (index.gateways[slug]) {
66
+ throw new Error(`Gateway "${slug}" already exists. Next: run hoolix gateway list.`);
67
+ }
68
+ const seenNamespaces = new Set();
69
+ const backends = [];
70
+ for (const include of uniqueIncludes) {
71
+ const meta = await getServerMetadata(include);
72
+ if ((meta.serverKind ?? 'docs-rag') !== 'mcp-server') {
73
+ throw new Error(`"${include}" is ${meta.serverKind ?? 'docs-rag'}, not mcp-server. Next: include only installed MCP server templates.`);
74
+ }
75
+ const templateId = meta.definition?.template?.id;
76
+ const namespace = dedupeNamespace(namespaceFromTemplate(templateId, meta.slug), seenNamespaces, meta.slug);
77
+ backends.push({ slug: meta.slug, namespace, templateId });
78
+ }
79
+ const now = new Date().toISOString();
80
+ const config = {
81
+ name,
82
+ slug,
83
+ authKey: generateAuthKey(),
84
+ backends,
85
+ createdAt: now,
86
+ lastUpdatedAt: now,
87
+ };
88
+ await fs.ensureDir(getGatewayDir(slug));
89
+ await fs.ensureDir(getGatewayDataDir(slug));
90
+ await fs.writeJson(getGatewayConfigPath(slug), config, { spaces: 2 });
91
+ index.gateways[slug] = { slug, path: getGatewayDir(slug) };
92
+ await saveGatewayIndex(index);
93
+ return config;
94
+ }
95
+ export async function listGateways() {
96
+ const index = await loadGatewayIndex();
97
+ const gateways = [];
98
+ for (const { slug } of Object.values(index.gateways)) {
99
+ try {
100
+ gateways.push(await getGateway(slug));
101
+ }
102
+ catch {
103
+ // Ignore corrupt gateway entries in list output.
104
+ }
105
+ }
106
+ return gateways.sort((a, b) => a.name.localeCompare(b.name));
107
+ }
108
+ export async function getGateway(slug) {
109
+ const pathToConfig = getGatewayConfigPath(slugify(slug));
110
+ if (!(await fs.pathExists(pathToConfig))) {
111
+ throw new Error(`Gateway "${slug}" not found. Next: run hoolix gateway list.`);
112
+ }
113
+ return GatewayConfigSchema.parse(await fs.readJson(pathToConfig));
114
+ }
115
+ //# sourceMappingURL=gateways.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateways.js","sourceRoot":"","sources":["../../src/core/gateways.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,8 @@ export interface AppPaths {
2
2
  data: string;
3
3
  config: string;
4
4
  servers: string;
5
+ gateways: string;
6
+ profiles: string;
5
7
  cache: string;
6
8
  }
7
9
  export declare function getPaths(): AppPaths;
@@ -12,4 +14,11 @@ export declare function getServerMetadataPath(slug: string): string;
12
14
  export declare function getServerDataDir(slug: string): string;
13
15
  export declare function getServerRuntimePath(slug: string): string;
14
16
  export declare function getServerCredentialsPath(slug: string): string;
17
+ export declare function getGatewayDir(name: string): string;
18
+ export declare function getGatewayConfigPath(name: string): string;
19
+ export declare function getGatewayRuntimePath(name: string): string;
20
+ export declare function getGatewayDataDir(name: string): string;
21
+ export declare function getProfileDir(name: string): string;
22
+ export declare function getProfileConfigPath(name: string): string;
23
+ export declare function getApprovalsPath(): string;
15
24
  //# sourceMappingURL=paths.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/core/paths.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAID,wBAAgB,QAAQ,IAAI,QAAQ,CAqBnC;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,QAAQ,CAAC,CAM3D;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7D"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/core/paths.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAID,wBAAgB,QAAQ,IAAI,QAAQ,CAyBnC;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,QAAQ,CAAC,CAQ3D;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC"}
@@ -13,12 +13,16 @@ export function getPaths() {
13
13
  // all share the same isolated filesystem root without test-only branches elsewhere.
14
14
  const data = process.env[DATA_DIR_ENV] || paths.data;
15
15
  const servers = path.join(data, 'servers');
16
+ const gateways = path.join(data, 'gateways');
17
+ const profiles = path.join(data, 'profiles');
16
18
  const config = path.join(data, 'config.json');
17
19
  const cache = path.join(data, 'cache');
18
20
  cachedPaths = {
19
21
  data,
20
22
  config,
21
23
  servers,
24
+ gateways,
25
+ profiles,
22
26
  cache,
23
27
  };
24
28
  return cachedPaths;
@@ -30,6 +34,8 @@ export async function ensureDirectories() {
30
34
  const p = getPaths();
31
35
  await fs.ensureDir(p.data);
32
36
  await fs.ensureDir(p.servers);
37
+ await fs.ensureDir(p.gateways);
38
+ await fs.ensureDir(p.profiles);
33
39
  await fs.ensureDir(p.cache);
34
40
  return p;
35
41
  }
@@ -48,4 +54,25 @@ export function getServerRuntimePath(slug) {
48
54
  export function getServerCredentialsPath(slug) {
49
55
  return path.join(getServerDir(slug), 'credentials.json');
50
56
  }
57
+ export function getGatewayDir(name) {
58
+ return path.join(getPaths().gateways, name);
59
+ }
60
+ export function getGatewayConfigPath(name) {
61
+ return path.join(getGatewayDir(name), 'gateway.json');
62
+ }
63
+ export function getGatewayRuntimePath(name) {
64
+ return path.join(getGatewayDir(name), '.runtime.json');
65
+ }
66
+ export function getGatewayDataDir(name) {
67
+ return path.join(getGatewayDir(name), 'data');
68
+ }
69
+ export function getProfileDir(name) {
70
+ return path.join(getPaths().profiles, name);
71
+ }
72
+ export function getProfileConfigPath(name) {
73
+ return path.join(getProfileDir(name), 'profile.json');
74
+ }
75
+ export function getApprovalsPath() {
76
+ return path.join(getPaths().data, 'approvals.json');
77
+ }
51
78
  //# sourceMappingURL=paths.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/core/paths.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,WAAW,CAAC;AACjC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,UAAU,CAAC;AAE1B,MAAM,QAAQ,GAAG,QAAQ,CAAC;AAC1B,MAAM,YAAY,GAAG,qBAAqB,CAAC;AAS3C,IAAI,WAAW,GAAoB,IAAI,CAAC;AAExC,MAAM,UAAU,QAAQ;IACtB,IAAI,WAAW;QAAE,OAAO,WAAW,CAAC;IAEpC,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;IAEjD,wEAAwE;IACxE,mFAAmF;IACnF,oFAAoF;IACpF,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC;IACrD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAEvC,WAAW,GAAG;QACZ,IAAI;QACJ,MAAM;QACN,OAAO;QACP,KAAK;KACN,CAAC;IAEF,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,WAAW,GAAG,IAAI,CAAC;AACrB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,MAAM,CAAC,GAAG,QAAQ,EAAE,CAAC;IACrB,MAAM,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC3B,MAAM,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAC9B,MAAM,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC5B,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,eAAe,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,eAAe,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,IAAY;IACnD,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,kBAAkB,CAAC,CAAC;AAC3D,CAAC"}
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/core/paths.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { Profile } from './profiles.js';
2
+ export type PolicyDecision = {
3
+ effect: 'allow';
4
+ reason?: string;
5
+ } | {
6
+ effect: 'deny';
7
+ reason: string;
8
+ } | {
9
+ effect: 'approve';
10
+ reason: string;
11
+ };
12
+ export declare function matchesPattern(pattern: string, value: string): boolean;
13
+ export declare function isWriteTool(toolName: string): boolean;
14
+ export declare function evaluatePolicy(input: {
15
+ profile: Profile | null;
16
+ gateway: string;
17
+ toolName: string;
18
+ args: unknown;
19
+ }): PolicyDecision;
20
+ //# sourceMappingURL=policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/core/policy.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,MAAM,cAAc,GACtB;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAO1C,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAEtE;AAMD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAErD;AAsDD,wBAAgB,cAAc,CAAC,KAAK,EAAE;IACpC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;CACf,GAAG,cAAc,CA0BjB"}
@@ -0,0 +1,95 @@
1
+ import path from 'node:path';
2
+ function wildcardToRegex(pattern) {
3
+ const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*');
4
+ return new RegExp(`^${escaped}$`, 'i');
5
+ }
6
+ export function matchesPattern(pattern, value) {
7
+ return wildcardToRegex(pattern).test(value);
8
+ }
9
+ function anyPatternMatches(patterns, value) {
10
+ return patterns.some((pattern) => matchesPattern(pattern, value));
11
+ }
12
+ export function isWriteTool(toolName) {
13
+ return /(^|[._-])(create|update|write|delete|remove|send|post|push|merge|mutate|insert|edit|apply)([._-]|$)/i.test(toolName);
14
+ }
15
+ function collectStrings(value, out = []) {
16
+ if (typeof value === 'string')
17
+ out.push(value);
18
+ else if (Array.isArray(value))
19
+ value.forEach((item) => collectStrings(item, out));
20
+ else if (value && typeof value === 'object')
21
+ Object.values(value).forEach((item) => collectStrings(item, out));
22
+ return out;
23
+ }
24
+ function normalizeFsPath(value) {
25
+ return path.resolve(value);
26
+ }
27
+ function isSubPath(candidate, root) {
28
+ const rel = path.relative(normalizeFsPath(root), normalizeFsPath(candidate));
29
+ return rel === '' || (!!rel && !rel.startsWith('..') && !path.isAbsolute(rel));
30
+ }
31
+ function sandboxDecision(profile, toolName, args) {
32
+ const strings = collectStrings(args);
33
+ const sandbox = profile.sandbox;
34
+ if (/filesystem|file|path/i.test(toolName)) {
35
+ for (const blocked of sandbox.blockedPaths) {
36
+ if (strings.some((candidate) => candidate.includes(blocked) || isSubPath(candidate, blocked))) {
37
+ return { effect: 'deny', reason: `blocked path matched "${blocked}"` };
38
+ }
39
+ }
40
+ if (sandbox.filesystemRoots.length > 0) {
41
+ const pathLike = strings.filter((candidate) => /[\\/]/.test(candidate) || /^[a-zA-Z]:/.test(candidate));
42
+ for (const candidate of pathLike) {
43
+ if (!sandbox.filesystemRoots.some((root) => isSubPath(candidate, root))) {
44
+ return { effect: 'deny', reason: `path outside allowed filesystem roots: ${candidate}` };
45
+ }
46
+ }
47
+ }
48
+ }
49
+ const urls = strings
50
+ .map((candidate) => {
51
+ try {
52
+ return new URL(candidate);
53
+ }
54
+ catch {
55
+ return null;
56
+ }
57
+ })
58
+ .filter((url) => !!url);
59
+ for (const url of urls) {
60
+ if (sandbox.blockedDomains.some((domain) => url.hostname === domain || url.hostname.endsWith(`.${domain}`))) {
61
+ return { effect: 'deny', reason: `blocked domain matched "${url.hostname}"` };
62
+ }
63
+ if (sandbox.allowedDomains.length > 0 && !sandbox.allowedDomains.some((domain) => url.hostname === domain || url.hostname.endsWith(`.${domain}`))) {
64
+ return { effect: 'deny', reason: `domain outside allowed list: ${url.hostname}` };
65
+ }
66
+ }
67
+ return null;
68
+ }
69
+ export function evaluatePolicy(input) {
70
+ const { profile, gateway, toolName, args } = input;
71
+ if (!profile)
72
+ return { effect: 'allow', reason: 'no profile' };
73
+ if (profile.allowedGateways.length > 0 && !profile.allowedGateways.includes(gateway)) {
74
+ return { effect: 'deny', reason: `profile "${profile.slug}" cannot access gateway "${gateway}"` };
75
+ }
76
+ if (profile.allowedTools.length > 0 && !anyPatternMatches(profile.allowedTools, toolName)) {
77
+ return { effect: 'deny', reason: `profile "${profile.slug}" cannot access tool "${toolName}"` };
78
+ }
79
+ const sandbox = sandboxDecision(profile, toolName, args);
80
+ if (sandbox)
81
+ return sandbox;
82
+ for (const rule of profile.policy.rules) {
83
+ if (matchesPattern(rule.match, toolName)) {
84
+ return { effect: rule.effect, reason: `matched rule ${rule.match}` };
85
+ }
86
+ }
87
+ if (profile.approvalMode === 'always')
88
+ return { effect: 'approve', reason: 'profile requires approval for every tool' };
89
+ if (profile.approvalMode === 'read-only' && isWriteTool(toolName))
90
+ return { effect: 'deny', reason: 'profile is read-only' };
91
+ if (profile.approvalMode === 'writes' && isWriteTool(toolName))
92
+ return { effect: 'approve', reason: 'profile requires approval for writes' };
93
+ return { effect: profile.policy.defaultEffect, reason: 'default policy' };
94
+ }
95
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/core/policy.ts"],"names":[],"mappings":"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"}