@peers-app/peers-sdk 0.22.0 → 0.23.1
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/dist/context/user-context-singleton.d.ts +42 -0
- package/dist/context/user-context-singleton.js +45 -0
- package/dist/contracts/__tests__/contract-proxy.test.js +51 -1
- package/dist/contracts/__tests__/contract-resolvers.test.js +30 -0
- package/dist/contracts/__tests__/playground.test.js +5 -2
- package/dist/contracts/__tests__/system-contracts.test.js +3 -0
- package/dist/contracts/contract-proxy.d.ts +6 -0
- package/dist/contracts/contract-proxy.js +34 -0
- package/dist/contracts/contract-resolvers.js +9 -1
- package/dist/contracts/index.d.ts +1 -0
- package/dist/contracts/index.js +5 -2
- package/dist/contracts/system/index.d.ts +2 -0
- package/dist/contracts/system/index.js +5 -1
- package/dist/contracts/system/tool-access-control-contract.d.ts +35 -0
- package/dist/contracts/system/tool-access-control-contract.js +70 -0
- package/dist/data/access-level.d.ts +72 -0
- package/dist/data/access-level.js +109 -0
- package/dist/data/access-level.test.d.ts +1 -0
- package/dist/data/access-level.test.js +53 -0
- package/dist/data/assistants.d.ts +24 -0
- package/dist/data/assistants.js +21 -0
- package/dist/data/group-member-roles.d.ts +9 -0
- package/dist/data/group-member-roles.js +9 -0
- package/dist/data/group-permissions.d.ts +55 -1
- package/dist/data/group-permissions.js +76 -6
- package/dist/data/index.d.ts +3 -0
- package/dist/data/index.js +3 -0
- package/dist/data/orm/sql.data-source.d.ts +10 -0
- package/dist/data/orm/sql.data-source.js +48 -30
- package/dist/data/orm/sql.data-source.test.js +13 -0
- package/dist/data/package-version-resolver.test.js +2 -0
- package/dist/data/tool-access-approvals.d.ts +126 -0
- package/dist/data/tool-access-approvals.js +86 -0
- package/dist/data/tool-access.d.ts +162 -0
- package/dist/data/tool-access.js +235 -0
- package/dist/data/tool-access.test.d.ts +1 -0
- package/dist/data/tool-access.test.js +159 -0
- package/dist/data/tools.d.ts +15 -0
- package/dist/data/tools.js +11 -0
- package/dist/data/workflow-logs.d.ts +5 -5
- package/dist/data/workflow-runs.d.ts +2 -2
- package/dist/device-pairing/types.d.ts +6 -6
- package/dist/system-ids.d.ts +18 -0
- package/dist/system-ids.js +19 -1
- package/package.json +1 -1
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { GroupMemberRole } from "./group-member-roles";
|
|
3
|
+
/**
|
|
4
|
+
* Named access-level constants on the same 0–100 scale as {@link GroupMemberRole}.
|
|
5
|
+
*
|
|
6
|
+
* Tools and Assistants store an integer in this range. Most callers use these
|
|
7
|
+
* named values; custom policies may use any integer from 0 through 100.
|
|
8
|
+
*
|
|
9
|
+
* `Self` (100) is operational authority in a personal context (or a group
|
|
10
|
+
* Founder). It is not connection {@link TrustLevel}.
|
|
11
|
+
*/
|
|
12
|
+
export declare const AccessLevel: {
|
|
13
|
+
readonly None: 0;
|
|
14
|
+
readonly Reader: 20;
|
|
15
|
+
readonly Writer: 40;
|
|
16
|
+
readonly Admin: 60;
|
|
17
|
+
readonly Owner: 80;
|
|
18
|
+
readonly Self: 100;
|
|
19
|
+
};
|
|
20
|
+
/** One of the named {@link AccessLevel} constants. */
|
|
21
|
+
export type NamedAccessLevel = (typeof AccessLevel)[keyof typeof AccessLevel];
|
|
22
|
+
/**
|
|
23
|
+
* Fail-closed default for unclassified tools and Assistants.
|
|
24
|
+
*
|
|
25
|
+
* Missing metadata is treated as {@link AccessLevel.Self} so a new package
|
|
26
|
+
* tool cannot run until someone explicitly lowers its requirement.
|
|
27
|
+
*/
|
|
28
|
+
export declare const DEFAULT_ACCESS_LEVEL: 100;
|
|
29
|
+
/** Inclusive minimum stored access level. */
|
|
30
|
+
export declare const MIN_ACCESS_LEVEL = 0;
|
|
31
|
+
/** Inclusive maximum stored access level. */
|
|
32
|
+
export declare const MAX_ACCESS_LEVEL = 100;
|
|
33
|
+
/**
|
|
34
|
+
* Zod schema for a stored access level: an integer from 0 through 100.
|
|
35
|
+
* Unspecified values default to {@link DEFAULT_ACCESS_LEVEL}.
|
|
36
|
+
*/
|
|
37
|
+
export declare const accessLevelSchema: z.ZodDefault<z.ZodNumber>;
|
|
38
|
+
/**
|
|
39
|
+
* Return a human-readable label for an access-level integer.
|
|
40
|
+
*
|
|
41
|
+
* Exact named values return `Self`, `Owner`, `Admin`, `Writer`, `Reader`, or
|
|
42
|
+
* `None`. Values between named tiers append `+` to the next-lower name
|
|
43
|
+
* (for example `61` → `Admin+`). Out-of-range numbers return `None`.
|
|
44
|
+
*
|
|
45
|
+
* @param value - Access level to label.
|
|
46
|
+
*/
|
|
47
|
+
export declare function getAccessLevelLabel(value: number): string;
|
|
48
|
+
/**
|
|
49
|
+
* Normalize a stored or missing access level to a safe integer.
|
|
50
|
+
*
|
|
51
|
+
* `undefined`, `null`, `NaN`, and non-integers become {@link DEFAULT_ACCESS_LEVEL}.
|
|
52
|
+
* Values outside 0–100 are clamped.
|
|
53
|
+
*
|
|
54
|
+
* @param value - Raw access level from a record or config.
|
|
55
|
+
*/
|
|
56
|
+
export declare function resolveAccessLevel(value: unknown): number;
|
|
57
|
+
/**
|
|
58
|
+
* Map a {@link GroupMemberRole} onto the access-level scale.
|
|
59
|
+
*
|
|
60
|
+
* Numeric values already match except the top label: group `Founder` (100)
|
|
61
|
+
* is access {@link AccessLevel.Self}.
|
|
62
|
+
*
|
|
63
|
+
* @param role - Group membership role.
|
|
64
|
+
*/
|
|
65
|
+
export declare function accessLevelFromGroupRole(role: GroupMemberRole): number;
|
|
66
|
+
/**
|
|
67
|
+
* Return the named access-level presets used by configuration UIs.
|
|
68
|
+
*/
|
|
69
|
+
export declare function listAccessLevelPresets(): ReadonlyArray<{
|
|
70
|
+
value: number;
|
|
71
|
+
label: string;
|
|
72
|
+
}>;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.accessLevelSchema = exports.MAX_ACCESS_LEVEL = exports.MIN_ACCESS_LEVEL = exports.DEFAULT_ACCESS_LEVEL = exports.AccessLevel = void 0;
|
|
4
|
+
exports.getAccessLevelLabel = getAccessLevelLabel;
|
|
5
|
+
exports.resolveAccessLevel = resolveAccessLevel;
|
|
6
|
+
exports.accessLevelFromGroupRole = accessLevelFromGroupRole;
|
|
7
|
+
exports.listAccessLevelPresets = listAccessLevelPresets;
|
|
8
|
+
const zod_1 = require("zod");
|
|
9
|
+
const group_member_roles_1 = require("./group-member-roles");
|
|
10
|
+
/**
|
|
11
|
+
* Named access-level constants on the same 0–100 scale as {@link GroupMemberRole}.
|
|
12
|
+
*
|
|
13
|
+
* Tools and Assistants store an integer in this range. Most callers use these
|
|
14
|
+
* named values; custom policies may use any integer from 0 through 100.
|
|
15
|
+
*
|
|
16
|
+
* `Self` (100) is operational authority in a personal context (or a group
|
|
17
|
+
* Founder). It is not connection {@link TrustLevel}.
|
|
18
|
+
*/
|
|
19
|
+
exports.AccessLevel = {
|
|
20
|
+
None: 0,
|
|
21
|
+
Reader: 20,
|
|
22
|
+
Writer: 40,
|
|
23
|
+
Admin: 60,
|
|
24
|
+
Owner: 80,
|
|
25
|
+
Self: 100,
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Fail-closed default for unclassified tools and Assistants.
|
|
29
|
+
*
|
|
30
|
+
* Missing metadata is treated as {@link AccessLevel.Self} so a new package
|
|
31
|
+
* tool cannot run until someone explicitly lowers its requirement.
|
|
32
|
+
*/
|
|
33
|
+
exports.DEFAULT_ACCESS_LEVEL = exports.AccessLevel.Self;
|
|
34
|
+
/** Inclusive minimum stored access level. */
|
|
35
|
+
exports.MIN_ACCESS_LEVEL = 0;
|
|
36
|
+
/** Inclusive maximum stored access level. */
|
|
37
|
+
exports.MAX_ACCESS_LEVEL = 100;
|
|
38
|
+
/**
|
|
39
|
+
* Zod schema for a stored access level: an integer from 0 through 100.
|
|
40
|
+
* Unspecified values default to {@link DEFAULT_ACCESS_LEVEL}.
|
|
41
|
+
*/
|
|
42
|
+
exports.accessLevelSchema = zod_1.z
|
|
43
|
+
.number()
|
|
44
|
+
.int()
|
|
45
|
+
.min(exports.MIN_ACCESS_LEVEL)
|
|
46
|
+
.max(exports.MAX_ACCESS_LEVEL)
|
|
47
|
+
.default(exports.DEFAULT_ACCESS_LEVEL);
|
|
48
|
+
const ACCESS_LEVEL_LABELS = [
|
|
49
|
+
{ level: exports.AccessLevel.Self, label: "Self" },
|
|
50
|
+
{ level: exports.AccessLevel.Owner, label: "Owner" },
|
|
51
|
+
{ level: exports.AccessLevel.Admin, label: "Admin" },
|
|
52
|
+
{ level: exports.AccessLevel.Writer, label: "Writer" },
|
|
53
|
+
{ level: exports.AccessLevel.Reader, label: "Reader" },
|
|
54
|
+
{ level: exports.AccessLevel.None, label: "None" },
|
|
55
|
+
];
|
|
56
|
+
/**
|
|
57
|
+
* Return a human-readable label for an access-level integer.
|
|
58
|
+
*
|
|
59
|
+
* Exact named values return `Self`, `Owner`, `Admin`, `Writer`, `Reader`, or
|
|
60
|
+
* `None`. Values between named tiers append `+` to the next-lower name
|
|
61
|
+
* (for example `61` → `Admin+`). Out-of-range numbers return `None`.
|
|
62
|
+
*
|
|
63
|
+
* @param value - Access level to label.
|
|
64
|
+
*/
|
|
65
|
+
function getAccessLevelLabel(value) {
|
|
66
|
+
for (const entry of ACCESS_LEVEL_LABELS) {
|
|
67
|
+
if (value >= entry.level) {
|
|
68
|
+
return value === entry.level ? entry.label : `${entry.label}+`;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return "None";
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Normalize a stored or missing access level to a safe integer.
|
|
75
|
+
*
|
|
76
|
+
* `undefined`, `null`, `NaN`, and non-integers become {@link DEFAULT_ACCESS_LEVEL}.
|
|
77
|
+
* Values outside 0–100 are clamped.
|
|
78
|
+
*
|
|
79
|
+
* @param value - Raw access level from a record or config.
|
|
80
|
+
*/
|
|
81
|
+
function resolveAccessLevel(value) {
|
|
82
|
+
if (typeof value !== "number" || !Number.isFinite(value) || !Number.isInteger(value)) {
|
|
83
|
+
return exports.DEFAULT_ACCESS_LEVEL;
|
|
84
|
+
}
|
|
85
|
+
if (value < exports.MIN_ACCESS_LEVEL)
|
|
86
|
+
return exports.MIN_ACCESS_LEVEL;
|
|
87
|
+
if (value > exports.MAX_ACCESS_LEVEL)
|
|
88
|
+
return exports.MAX_ACCESS_LEVEL;
|
|
89
|
+
return value;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Map a {@link GroupMemberRole} onto the access-level scale.
|
|
93
|
+
*
|
|
94
|
+
* Numeric values already match except the top label: group `Founder` (100)
|
|
95
|
+
* is access {@link AccessLevel.Self}.
|
|
96
|
+
*
|
|
97
|
+
* @param role - Group membership role.
|
|
98
|
+
*/
|
|
99
|
+
function accessLevelFromGroupRole(role) {
|
|
100
|
+
return role === group_member_roles_1.GroupMemberRole.Founder ? exports.AccessLevel.Self : role;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Return the named access-level presets used by configuration UIs.
|
|
104
|
+
*/
|
|
105
|
+
function listAccessLevelPresets() {
|
|
106
|
+
return ACCESS_LEVEL_LABELS.slice()
|
|
107
|
+
.reverse()
|
|
108
|
+
.map(({ level, label }) => ({ value: level, label }));
|
|
109
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const group_member_roles_1 = require("./group-member-roles");
|
|
4
|
+
const access_level_1 = require("./access-level");
|
|
5
|
+
describe("accessLevelSchema", () => {
|
|
6
|
+
it("defaults missing values to Self (100)", () => {
|
|
7
|
+
expect(access_level_1.accessLevelSchema.parse(undefined)).toBe(access_level_1.AccessLevel.Self);
|
|
8
|
+
expect(access_level_1.DEFAULT_ACCESS_LEVEL).toBe(100);
|
|
9
|
+
});
|
|
10
|
+
it("accepts custom integers between named tiers", () => {
|
|
11
|
+
expect(access_level_1.accessLevelSchema.parse(45)).toBe(45);
|
|
12
|
+
});
|
|
13
|
+
it("rejects values outside 0–100", () => {
|
|
14
|
+
expect(access_level_1.accessLevelSchema.safeParse(-1).success).toBe(false);
|
|
15
|
+
expect(access_level_1.accessLevelSchema.safeParse(101).success).toBe(false);
|
|
16
|
+
expect(access_level_1.accessLevelSchema.safeParse(40.5).success).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
describe("getAccessLevelLabel", () => {
|
|
20
|
+
it("labels named tiers", () => {
|
|
21
|
+
expect((0, access_level_1.getAccessLevelLabel)(0)).toBe("None");
|
|
22
|
+
expect((0, access_level_1.getAccessLevelLabel)(20)).toBe("Reader");
|
|
23
|
+
expect((0, access_level_1.getAccessLevelLabel)(40)).toBe("Writer");
|
|
24
|
+
expect((0, access_level_1.getAccessLevelLabel)(60)).toBe("Admin");
|
|
25
|
+
expect((0, access_level_1.getAccessLevelLabel)(80)).toBe("Owner");
|
|
26
|
+
expect((0, access_level_1.getAccessLevelLabel)(100)).toBe("Self");
|
|
27
|
+
});
|
|
28
|
+
it("labels in-between values with +", () => {
|
|
29
|
+
expect((0, access_level_1.getAccessLevelLabel)(61)).toBe("Admin+");
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
describe("resolveAccessLevel", () => {
|
|
33
|
+
it("fail-closes invalid values to 100", () => {
|
|
34
|
+
expect((0, access_level_1.resolveAccessLevel)(undefined)).toBe(100);
|
|
35
|
+
expect((0, access_level_1.resolveAccessLevel)("40")).toBe(100);
|
|
36
|
+
expect((0, access_level_1.resolveAccessLevel)(Number.NaN)).toBe(100);
|
|
37
|
+
});
|
|
38
|
+
it("clamps out-of-range integers", () => {
|
|
39
|
+
expect((0, access_level_1.resolveAccessLevel)(-5)).toBe(0);
|
|
40
|
+
expect((0, access_level_1.resolveAccessLevel)(200)).toBe(100);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
describe("accessLevelFromGroupRole", () => {
|
|
44
|
+
it("maps Founder to Self 100", () => {
|
|
45
|
+
expect((0, access_level_1.accessLevelFromGroupRole)(group_member_roles_1.GroupMemberRole.Founder)).toBe(access_level_1.AccessLevel.Self);
|
|
46
|
+
expect((0, access_level_1.accessLevelFromGroupRole)(group_member_roles_1.GroupMemberRole.Admin)).toBe(access_level_1.AccessLevel.Admin);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
describe("listAccessLevelPresets", () => {
|
|
50
|
+
it("returns named presets in ascending order", () => {
|
|
51
|
+
expect((0, access_level_1.listAccessLevelPresets)().map((p) => p.value)).toEqual([0, 20, 40, 60, 80, 100]);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import type { DataContext } from "../context/data-context";
|
|
3
|
+
/** How an Assistant selects tools for each run. */
|
|
3
4
|
export declare enum ToolInclusionStrategy {
|
|
4
5
|
Fixed = "Fixed",
|
|
5
6
|
Linked = "Linked",
|
|
6
7
|
Relevant = "Relevant"
|
|
7
8
|
}
|
|
9
|
+
/** Zod schema for a persisted {@link IAssistant} row. */
|
|
8
10
|
export declare const assistantSchema: z.ZodObject<{
|
|
9
11
|
assistantId: z.ZodEffects<z.ZodString, string, string>;
|
|
10
12
|
name: z.ZodString;
|
|
@@ -16,8 +18,10 @@ export declare const assistantSchema: z.ZodObject<{
|
|
|
16
18
|
toolsToInclude: z.ZodDefault<z.ZodString>;
|
|
17
19
|
toolInclusionStrategy: z.ZodDefault<z.ZodNativeEnum<typeof ToolInclusionStrategy>>;
|
|
18
20
|
packageId: z.ZodOptional<z.ZodEffects<z.ZodString, string, string>>;
|
|
21
|
+
accessLevel: z.ZodDefault<z.ZodNumber>;
|
|
19
22
|
}, "strip", z.ZodTypeAny, {
|
|
20
23
|
name: string;
|
|
24
|
+
accessLevel: number;
|
|
21
25
|
assistantId: string;
|
|
22
26
|
createdAt: Date;
|
|
23
27
|
assistantRunnerToolId: string;
|
|
@@ -34,6 +38,7 @@ export declare const assistantSchema: z.ZodObject<{
|
|
|
34
38
|
assistantId: string;
|
|
35
39
|
description?: string | undefined;
|
|
36
40
|
packageId?: string | undefined;
|
|
41
|
+
accessLevel?: number | undefined;
|
|
37
42
|
createdAt?: Date | undefined;
|
|
38
43
|
updatedAt?: Date | undefined;
|
|
39
44
|
assistantRunnerToolId?: string | undefined;
|
|
@@ -41,9 +46,16 @@ export declare const assistantSchema: z.ZodObject<{
|
|
|
41
46
|
toolsToInclude?: string | undefined;
|
|
42
47
|
toolInclusionStrategy?: ToolInclusionStrategy | undefined;
|
|
43
48
|
}>;
|
|
49
|
+
/** An Assistant definition stored in the Assistants table. */
|
|
44
50
|
export type IAssistant = z.infer<typeof assistantSchema>;
|
|
51
|
+
/**
|
|
52
|
+
* Accessor for the Assistants table.
|
|
53
|
+
*
|
|
54
|
+
* @param dataContext - Optional data context; defaults to the current singleton.
|
|
55
|
+
*/
|
|
45
56
|
export declare function Assistants(dataContext?: DataContext): import("..").Table<{
|
|
46
57
|
name: string;
|
|
58
|
+
accessLevel: number;
|
|
47
59
|
assistantId: string;
|
|
48
60
|
createdAt: Date;
|
|
49
61
|
assistantRunnerToolId: string;
|
|
@@ -66,8 +78,15 @@ export declare const userPrimaryAssistantVar: import("./persistent-vars").Persis
|
|
|
66
78
|
* their own preference. Can be set by group admins. Synced to all group members.
|
|
67
79
|
*/
|
|
68
80
|
export declare const groupPrimaryAssistantVar: import("./persistent-vars").PersistentVar<string | undefined>;
|
|
81
|
+
/**
|
|
82
|
+
* Resolve the current user's primary Assistant, falling back to the group
|
|
83
|
+
* default and then the built-in Shell Assistant.
|
|
84
|
+
*
|
|
85
|
+
* @param dataContext - Optional data context for the lookup.
|
|
86
|
+
*/
|
|
69
87
|
export declare const getPrimaryAssistant: (dataContext?: DataContext) => Promise<{
|
|
70
88
|
name: string;
|
|
89
|
+
accessLevel: number;
|
|
71
90
|
assistantId: string;
|
|
72
91
|
createdAt: Date;
|
|
73
92
|
assistantRunnerToolId: string;
|
|
@@ -80,4 +99,9 @@ export declare const getPrimaryAssistant: (dataContext?: DataContext) => Promise
|
|
|
80
99
|
packageId?: string | undefined;
|
|
81
100
|
updatedAt?: Date | undefined;
|
|
82
101
|
}>;
|
|
102
|
+
/**
|
|
103
|
+
* Return Assistant ids mentioned in markdown (`<@assistant:name:id>`).
|
|
104
|
+
*
|
|
105
|
+
* @param message - Message markdown that may contain mentions.
|
|
106
|
+
*/
|
|
83
107
|
export declare function getAllAssistantIdsMentioned(message: string): Promise<string[]>;
|
package/dist/data/assistants.js
CHANGED
|
@@ -8,15 +8,18 @@ const user_context_singleton_1 = require("../context/user-context-singleton");
|
|
|
8
8
|
const mentions_1 = require("../mentions");
|
|
9
9
|
const system_ids_1 = require("../system-ids");
|
|
10
10
|
const zod_types_1 = require("../types/zod-types");
|
|
11
|
+
const access_level_1 = require("./access-level");
|
|
11
12
|
const table_definitions_system_1 = require("./orm/table-definitions.system");
|
|
12
13
|
const types_1 = require("./orm/types");
|
|
13
14
|
const persistent_vars_1 = require("./persistent-vars");
|
|
15
|
+
/** How an Assistant selects tools for each run. */
|
|
14
16
|
var ToolInclusionStrategy;
|
|
15
17
|
(function (ToolInclusionStrategy) {
|
|
16
18
|
ToolInclusionStrategy["Fixed"] = "Fixed";
|
|
17
19
|
ToolInclusionStrategy["Linked"] = "Linked";
|
|
18
20
|
ToolInclusionStrategy["Relevant"] = "Relevant";
|
|
19
21
|
})(ToolInclusionStrategy || (exports.ToolInclusionStrategy = ToolInclusionStrategy = {}));
|
|
22
|
+
/** Zod schema for a persisted {@link IAssistant} row. */
|
|
20
23
|
exports.assistantSchema = zod_1.z.object({
|
|
21
24
|
assistantId: zod_types_1.zodPeerId,
|
|
22
25
|
name: zod_1.z.string(),
|
|
@@ -47,6 +50,7 @@ exports.assistantSchema = zod_1.z.object({
|
|
|
47
50
|
"- **Relevant** - `Linked` plus tools matching the context of the conversation determined via vector search (embeddings) of the tools descriptions.",
|
|
48
51
|
].join("\n")),
|
|
49
52
|
packageId: zod_types_1.zodPeerId.optional().describe("The package that installed this assistant, if any"),
|
|
53
|
+
accessLevel: access_level_1.accessLevelSchema.describe("Minimum user access to invoke this assistant, and the level it may run automatically. Unclassified assistants default to 100 (Self)."),
|
|
50
54
|
});
|
|
51
55
|
const metaData = {
|
|
52
56
|
name: "Assistants",
|
|
@@ -55,8 +59,14 @@ const metaData = {
|
|
|
55
59
|
fields: (0, types_1.schemaToFields)(exports.assistantSchema),
|
|
56
60
|
iconClassName: "bi bi-person-fill-gear",
|
|
57
61
|
indexes: [{ fields: ["name"] }],
|
|
62
|
+
versionNumber: 1,
|
|
58
63
|
};
|
|
59
64
|
(0, table_definitions_system_1.registerSystemTableDefinition)(metaData, exports.assistantSchema);
|
|
65
|
+
/**
|
|
66
|
+
* Accessor for the Assistants table.
|
|
67
|
+
*
|
|
68
|
+
* @param dataContext - Optional data context; defaults to the current singleton.
|
|
69
|
+
*/
|
|
60
70
|
function Assistants(dataContext) {
|
|
61
71
|
return (0, user_context_singleton_1.getTableContainer)(dataContext).getTable(metaData, exports.assistantSchema);
|
|
62
72
|
}
|
|
@@ -70,6 +80,12 @@ exports.userPrimaryAssistantVar = (0, persistent_vars_1.groupUserVar)("userPrima
|
|
|
70
80
|
* their own preference. Can be set by group admins. Synced to all group members.
|
|
71
81
|
*/
|
|
72
82
|
exports.groupPrimaryAssistantVar = (0, persistent_vars_1.groupVar)("groupPrimaryAssistantId");
|
|
83
|
+
/**
|
|
84
|
+
* Resolve the current user's primary Assistant, falling back to the group
|
|
85
|
+
* default and then the built-in Shell Assistant.
|
|
86
|
+
*
|
|
87
|
+
* @param dataContext - Optional data context for the lookup.
|
|
88
|
+
*/
|
|
73
89
|
const getPrimaryAssistant = async (dataContext) => {
|
|
74
90
|
await exports.userPrimaryAssistantVar.loadingPromise;
|
|
75
91
|
const userAssistantId = (0, exports.userPrimaryAssistantVar)();
|
|
@@ -91,6 +107,11 @@ const getPrimaryAssistant = async (dataContext) => {
|
|
|
91
107
|
return fallback;
|
|
92
108
|
};
|
|
93
109
|
exports.getPrimaryAssistant = getPrimaryAssistant;
|
|
110
|
+
/**
|
|
111
|
+
* Return Assistant ids mentioned in markdown (`<@assistant:name:id>`).
|
|
112
|
+
*
|
|
113
|
+
* @param message - Message markdown that may contain mentions.
|
|
114
|
+
*/
|
|
94
115
|
async function getAllAssistantIdsMentioned(message) {
|
|
95
116
|
const mentions = (0, mentions_1.getAllMentions)(message);
|
|
96
117
|
return mentions.filter((m) => m.kind === "assistant").map((m) => m.id);
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Numeric group membership roles. The same 0–100 scale is used for tool and
|
|
3
|
+
* Assistant {@link AccessLevel} values (`Founder` maps to access `Self`).
|
|
4
|
+
*/
|
|
1
5
|
export declare enum GroupMemberRole {
|
|
2
6
|
None = 0,
|
|
3
7
|
Reader = 20,
|
|
@@ -6,4 +10,9 @@ export declare enum GroupMemberRole {
|
|
|
6
10
|
Owner = 80,
|
|
7
11
|
Founder = 100
|
|
8
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Return a human-readable group-role label, using `+` for in-between values.
|
|
15
|
+
*
|
|
16
|
+
* @param value - Numeric role or access-like integer.
|
|
17
|
+
*/
|
|
9
18
|
export declare function getRoleLabel(value: number): string;
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.GroupMemberRole = void 0;
|
|
4
4
|
exports.getRoleLabel = getRoleLabel;
|
|
5
|
+
/**
|
|
6
|
+
* Numeric group membership roles. The same 0–100 scale is used for tool and
|
|
7
|
+
* Assistant {@link AccessLevel} values (`Founder` maps to access `Self`).
|
|
8
|
+
*/
|
|
5
9
|
var GroupMemberRole;
|
|
6
10
|
(function (GroupMemberRole) {
|
|
7
11
|
GroupMemberRole[GroupMemberRole["None"] = 0] = "None";
|
|
@@ -11,6 +15,11 @@ var GroupMemberRole;
|
|
|
11
15
|
GroupMemberRole[GroupMemberRole["Owner"] = 80] = "Owner";
|
|
12
16
|
GroupMemberRole[GroupMemberRole["Founder"] = 100] = "Founder";
|
|
13
17
|
})(GroupMemberRole || (exports.GroupMemberRole = GroupMemberRole = {}));
|
|
18
|
+
/**
|
|
19
|
+
* Return a human-readable group-role label, using `+` for in-between values.
|
|
20
|
+
*
|
|
21
|
+
* @param value - Numeric role or access-like integer.
|
|
22
|
+
*/
|
|
14
23
|
function getRoleLabel(value) {
|
|
15
24
|
const roleEntries = Object.entries(GroupMemberRole)
|
|
16
25
|
.filter(([_key, val]) => typeof val === "number")
|
|
@@ -1,8 +1,62 @@
|
|
|
1
|
+
import type { DataContext } from "../context/data-context";
|
|
2
|
+
import type { UserContext } from "../context/user-context";
|
|
1
3
|
import { GroupMemberRole } from "./group-member-roles";
|
|
2
4
|
import type { IGroupMember } from "./group-members";
|
|
3
5
|
import type { IGroup } from "./groups";
|
|
4
6
|
export { GroupMemberRole };
|
|
5
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Return a user's {@link GroupMemberRole} in `groupId`.
|
|
9
|
+
*
|
|
10
|
+
* Missing groups and the group's founder resolve to {@link GroupMemberRole.Founder},
|
|
11
|
+
* which is how a personal context (no Groups row) becomes access 100.
|
|
12
|
+
*
|
|
13
|
+
* Prefer passing `userContext` from the provider that owns the data. The
|
|
14
|
+
* process singleton is only a fallback and is not awaited — multi-device
|
|
15
|
+
* tests never set it, and hanging here would stall contract calls.
|
|
16
|
+
*
|
|
17
|
+
* @param groupId - Group id, or the user's id for their personal context.
|
|
18
|
+
* @param userId - User whose role is requested.
|
|
19
|
+
* @param userContext - Provider-owned context. Falls back to {@link peekUserContext}.
|
|
20
|
+
* @throws If neither an explicit context nor the process singleton is available.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getUserRole(groupId: string, userId: string, userContext?: UserContext): Promise<GroupMemberRole>;
|
|
23
|
+
/**
|
|
24
|
+
* Resolve a group role from the signing public key of a Users record.
|
|
25
|
+
*
|
|
26
|
+
* Uses {@link peekUserContext}; throws if the process singleton is unset.
|
|
27
|
+
*
|
|
28
|
+
* @param groupId - Group or personal context id.
|
|
29
|
+
* @param publicKey - User public key that signed a record.
|
|
30
|
+
*/
|
|
6
31
|
export declare function getUserRoleFromPublicKey(groupId: string, publicKey: string): Promise<GroupMemberRole>;
|
|
32
|
+
/**
|
|
33
|
+
* Return the current user's access level in `dataContext`.
|
|
34
|
+
*
|
|
35
|
+
* Personal contexts (no `groupId`) use the user's id and resolve to 100.
|
|
36
|
+
*
|
|
37
|
+
* @param dataContext - Context whose group/personal role is evaluated.
|
|
38
|
+
*/
|
|
39
|
+
export declare function getCurrentUserAccessLevel(dataContext: DataContext): Promise<number>;
|
|
40
|
+
/**
|
|
41
|
+
* Return `userId`'s access level in `dataContext`.
|
|
42
|
+
*
|
|
43
|
+
* @param dataContext - Context whose group/personal role is evaluated.
|
|
44
|
+
* @param userId - User to resolve.
|
|
45
|
+
*/
|
|
46
|
+
export declare function getUserAccessLevel(dataContext: DataContext, userId: string): Promise<number>;
|
|
47
|
+
/**
|
|
48
|
+
* Verify that a group record was signed by an Admin+ member (Founder to change founder).
|
|
49
|
+
*
|
|
50
|
+
* @param group - Proposed group record.
|
|
51
|
+
* @param oldGroup - Previous record when this is an update.
|
|
52
|
+
*/
|
|
7
53
|
export declare function verifyGroupSignature(group: IGroup, oldGroup?: IGroup): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Return whether a group-member write is signed by someone allowed to make it.
|
|
56
|
+
*
|
|
57
|
+
* @param groupId - Group the membership belongs to.
|
|
58
|
+
* @param newGroupMember - Proposed membership row.
|
|
59
|
+
* @param oldGroupMember - Previous row when this is an update.
|
|
60
|
+
* @param signerRole - Optional precomputed signer role.
|
|
61
|
+
*/
|
|
8
62
|
export declare function isGroupMemberSignatureValid(groupId: string, newGroupMember: IGroupMember, oldGroupMember?: IGroupMember, signerRole?: GroupMemberRole): Promise<boolean>;
|
|
@@ -3,19 +3,41 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.GroupMemberRole = void 0;
|
|
4
4
|
exports.getUserRole = getUserRole;
|
|
5
5
|
exports.getUserRoleFromPublicKey = getUserRoleFromPublicKey;
|
|
6
|
+
exports.getCurrentUserAccessLevel = getCurrentUserAccessLevel;
|
|
7
|
+
exports.getUserAccessLevel = getUserAccessLevel;
|
|
6
8
|
exports.verifyGroupSignature = verifyGroupSignature;
|
|
7
9
|
exports.isGroupMemberSignatureValid = isGroupMemberSignatureValid;
|
|
8
10
|
const context_1 = require("../context");
|
|
9
11
|
const keys_1 = require("../keys");
|
|
12
|
+
const access_level_1 = require("./access-level");
|
|
10
13
|
const group_member_roles_1 = require("./group-member-roles");
|
|
11
14
|
Object.defineProperty(exports, "GroupMemberRole", { enumerable: true, get: function () { return group_member_roles_1.GroupMemberRole; } });
|
|
12
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Return a user's {@link GroupMemberRole} in `groupId`.
|
|
17
|
+
*
|
|
18
|
+
* Missing groups and the group's founder resolve to {@link GroupMemberRole.Founder},
|
|
19
|
+
* which is how a personal context (no Groups row) becomes access 100.
|
|
20
|
+
*
|
|
21
|
+
* Prefer passing `userContext` from the provider that owns the data. The
|
|
22
|
+
* process singleton is only a fallback and is not awaited — multi-device
|
|
23
|
+
* tests never set it, and hanging here would stall contract calls.
|
|
24
|
+
*
|
|
25
|
+
* @param groupId - Group id, or the user's id for their personal context.
|
|
26
|
+
* @param userId - User whose role is requested.
|
|
27
|
+
* @param userContext - Provider-owned context. Falls back to {@link peekUserContext}.
|
|
28
|
+
* @throws If neither an explicit context nor the process singleton is available.
|
|
29
|
+
*/
|
|
30
|
+
async function getUserRole(groupId, userId, userContext) {
|
|
13
31
|
const { Groups } = await Promise.resolve().then(() => require("./groups"));
|
|
14
32
|
const { GroupMembers } = await Promise.resolve().then(() => require("./group-members"));
|
|
15
|
-
const
|
|
16
|
-
|
|
33
|
+
const ctx = userContext ?? (0, context_1.peekUserContext)();
|
|
34
|
+
if (!ctx) {
|
|
35
|
+
throw new Error("User context is not available");
|
|
36
|
+
}
|
|
37
|
+
await ctx.loadingPromise;
|
|
38
|
+
const groupDataContext = ctx.getDataContext(groupId);
|
|
17
39
|
const group = (await Groups(groupDataContext).get(groupId)) ||
|
|
18
|
-
(await Groups(
|
|
40
|
+
(await Groups(ctx.userDataContext).get(groupId));
|
|
19
41
|
// If the group doesn't exist or the current user is explicitly the founder, return Founder role
|
|
20
42
|
if (!group || group.founderUserId === userId) {
|
|
21
43
|
return group_member_roles_1.GroupMemberRole.Founder;
|
|
@@ -26,17 +48,57 @@ async function getUserRole(groupId, userId) {
|
|
|
26
48
|
}
|
|
27
49
|
return group.publicRole || group_member_roles_1.GroupMemberRole.None;
|
|
28
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Resolve a group role from the signing public key of a Users record.
|
|
53
|
+
*
|
|
54
|
+
* Uses {@link peekUserContext}; throws if the process singleton is unset.
|
|
55
|
+
*
|
|
56
|
+
* @param groupId - Group or personal context id.
|
|
57
|
+
* @param publicKey - User public key that signed a record.
|
|
58
|
+
*/
|
|
29
59
|
async function getUserRoleFromPublicKey(groupId, publicKey) {
|
|
30
60
|
const { Users } = await Promise.resolve().then(() => require("./users"));
|
|
31
|
-
const userContext =
|
|
61
|
+
const userContext = (0, context_1.peekUserContext)();
|
|
62
|
+
if (!userContext) {
|
|
63
|
+
throw new Error("User context is not available");
|
|
64
|
+
}
|
|
65
|
+
await userContext.loadingPromise;
|
|
32
66
|
const groupDataContext = userContext.getDataContext(groupId);
|
|
33
67
|
const user = (await Users(groupDataContext).findOne({ publicKey })) ||
|
|
34
68
|
(await Users(userContext.userDataContext).findOne({ publicKey }));
|
|
35
69
|
if (user) {
|
|
36
|
-
return getUserRole(groupId, user?.userId);
|
|
70
|
+
return getUserRole(groupId, user?.userId, userContext);
|
|
37
71
|
}
|
|
38
72
|
return group_member_roles_1.GroupMemberRole.None;
|
|
39
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Return the current user's access level in `dataContext`.
|
|
76
|
+
*
|
|
77
|
+
* Personal contexts (no `groupId`) use the user's id and resolve to 100.
|
|
78
|
+
*
|
|
79
|
+
* @param dataContext - Context whose group/personal role is evaluated.
|
|
80
|
+
*/
|
|
81
|
+
async function getCurrentUserAccessLevel(dataContext) {
|
|
82
|
+
const userId = dataContext.userContext.userId;
|
|
83
|
+
return getUserAccessLevel(dataContext, userId);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Return `userId`'s access level in `dataContext`.
|
|
87
|
+
*
|
|
88
|
+
* @param dataContext - Context whose group/personal role is evaluated.
|
|
89
|
+
* @param userId - User to resolve.
|
|
90
|
+
*/
|
|
91
|
+
async function getUserAccessLevel(dataContext, userId) {
|
|
92
|
+
const contextKey = dataContext.groupId ?? dataContext.userContext.userId;
|
|
93
|
+
const role = await getUserRole(contextKey, userId, dataContext.userContext);
|
|
94
|
+
return (0, access_level_1.accessLevelFromGroupRole)(role);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Verify that a group record was signed by an Admin+ member (Founder to change founder).
|
|
98
|
+
*
|
|
99
|
+
* @param group - Proposed group record.
|
|
100
|
+
* @param oldGroup - Previous record when this is an update.
|
|
101
|
+
*/
|
|
40
102
|
async function verifyGroupSignature(group, oldGroup) {
|
|
41
103
|
(0, keys_1.verifyObjectSignature)(group);
|
|
42
104
|
const publicKey = (0, keys_1.getPublicKeyFromObjectSignature)(group) ?? "";
|
|
@@ -50,6 +112,14 @@ async function verifyGroupSignature(group, oldGroup) {
|
|
|
50
112
|
throw new Error("Only group admins can modify group settings");
|
|
51
113
|
}
|
|
52
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* Return whether a group-member write is signed by someone allowed to make it.
|
|
117
|
+
*
|
|
118
|
+
* @param groupId - Group the membership belongs to.
|
|
119
|
+
* @param newGroupMember - Proposed membership row.
|
|
120
|
+
* @param oldGroupMember - Previous row when this is an update.
|
|
121
|
+
* @param signerRole - Optional precomputed signer role.
|
|
122
|
+
*/
|
|
53
123
|
async function isGroupMemberSignatureValid(groupId, newGroupMember, oldGroupMember, signerRole) {
|
|
54
124
|
oldGroupMember ??= newGroupMember;
|
|
55
125
|
// Basic signature verification
|
package/dist/data/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export * from "./access-level";
|
|
1
2
|
export * from "./assistants";
|
|
2
3
|
export * from "./change-tracking";
|
|
3
4
|
export * from "./channels";
|
|
@@ -20,6 +21,8 @@ export * from "./peer-types";
|
|
|
20
21
|
export * from "./persistent-vars";
|
|
21
22
|
export * from "./sync-recovery-queue";
|
|
22
23
|
export * from "./table-definitions-table";
|
|
24
|
+
export * from "./tool-access";
|
|
25
|
+
export * from "./tool-access-approvals";
|
|
23
26
|
export * from "./tool-tests";
|
|
24
27
|
export * from "./tools";
|
|
25
28
|
export * from "./user-permissions";
|
package/dist/data/index.js
CHANGED
|
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./access-level"), exports);
|
|
17
18
|
__exportStar(require("./assistants"), exports);
|
|
18
19
|
__exportStar(require("./change-tracking"), exports);
|
|
19
20
|
__exportStar(require("./channels"), exports);
|
|
@@ -36,6 +37,8 @@ __exportStar(require("./peer-types"), exports);
|
|
|
36
37
|
__exportStar(require("./persistent-vars"), exports);
|
|
37
38
|
__exportStar(require("./sync-recovery-queue"), exports);
|
|
38
39
|
__exportStar(require("./table-definitions-table"), exports);
|
|
40
|
+
__exportStar(require("./tool-access"), exports);
|
|
41
|
+
__exportStar(require("./tool-access-approvals"), exports);
|
|
39
42
|
__exportStar(require("./tool-tests"), exports);
|
|
40
43
|
__exportStar(require("./tools"), exports);
|
|
41
44
|
__exportStar(require("./user-permissions"), exports);
|
|
@@ -34,6 +34,16 @@ export declare class SQLDataSource<T extends {
|
|
|
34
34
|
delete(idOrRecord: string | T): Promise<void>;
|
|
35
35
|
dropTableIfExists(): Promise<void>;
|
|
36
36
|
clearTable(): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Validate `record` and copy Zod defaults onto missing keys so NOT NULL
|
|
39
|
+
* columns (for example `accessLevel`) are written on insert.
|
|
40
|
+
*/
|
|
41
|
+
private applySchemaDefaults;
|
|
42
|
+
/**
|
|
43
|
+
* Columns to SET on update. Required fields that are missing are omitted so
|
|
44
|
+
* older peers without a new column do not overwrite a local value with NULL.
|
|
45
|
+
*/
|
|
46
|
+
private fieldsForUpdate;
|
|
37
47
|
initRecord(data?: Partial<T>): T;
|
|
38
48
|
/**
|
|
39
49
|
* Synchronous insert for use within transactions.
|