@opengeni/core 2.7.5-canary.0 → 2.7.5-canary.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/domain/github-action-policies.d.ts +36 -0
- package/dist/domain/pr-review.d.ts +1 -1
- package/dist/domain/sessions.d.ts +3 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +116 -1
- package/dist/index.js.map +1 -1
- package/package.json +12 -12
- package/src/application/new-session-drafts.ts +6 -0
- package/src/domain/github-action-policies.ts +169 -0
- package/src/domain/sessions.ts +5 -3
- package/src/index.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/core",
|
|
3
|
-
"version": "2.7.5-canary.
|
|
3
|
+
"version": "2.7.5-canary.2",
|
|
4
4
|
"description": "OpenGeni framework-agnostic core: the domain, access, and billing layers (neutral access, off-HTTP V2 surface). Behavior-preserving extraction from apps/api — keeps Hono's HTTPException for error throwing (typed-errors cleanup deferred).",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -54,17 +54,17 @@
|
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
57
|
-
"@opengeni/capabilities": "^0.3.2-canary.
|
|
58
|
-
"@opengeni/codex": "^0.2.21-canary.
|
|
59
|
-
"@opengeni/config": "^1.0.0-canary.
|
|
60
|
-
"@opengeni/contracts": "^2.13.0-canary.
|
|
61
|
-
"@opengeni/db": "^4.0.0-canary.
|
|
62
|
-
"@opengeni/documents": "^0.8.19-canary.
|
|
63
|
-
"@opengeni/events": "^0.4.17-canary.
|
|
64
|
-
"@opengeni/network": "^0.3.0-canary.
|
|
65
|
-
"@opengeni/observability": "^0.8.19-canary.
|
|
66
|
-
"@opengeni/runtime": "^2.3.0-canary.
|
|
67
|
-
"@opengeni/storage": "^0.2.120-canary.
|
|
57
|
+
"@opengeni/capabilities": "^0.3.2-canary.2",
|
|
58
|
+
"@opengeni/codex": "^0.2.21-canary.2",
|
|
59
|
+
"@opengeni/config": "^1.0.0-canary.2",
|
|
60
|
+
"@opengeni/contracts": "^2.13.0-canary.2",
|
|
61
|
+
"@opengeni/db": "^4.0.0-canary.2",
|
|
62
|
+
"@opengeni/documents": "^0.8.19-canary.2",
|
|
63
|
+
"@opengeni/events": "^0.4.17-canary.2",
|
|
64
|
+
"@opengeni/network": "^0.3.0-canary.2",
|
|
65
|
+
"@opengeni/observability": "^0.8.19-canary.2",
|
|
66
|
+
"@opengeni/runtime": "^2.3.0-canary.2",
|
|
67
|
+
"@opengeni/storage": "^0.2.120-canary.2",
|
|
68
68
|
"hono": "^4.12.18",
|
|
69
69
|
"zod": "^4.2.1"
|
|
70
70
|
},
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
getSandbox,
|
|
12
12
|
getVariableSet,
|
|
13
13
|
NewSessionDraftAccessError,
|
|
14
|
+
newSessionDraftSelectedProjectChannelId,
|
|
14
15
|
newSessionDraftToolsProvided,
|
|
15
16
|
newSessionSelectionHistory,
|
|
16
17
|
publicNewSessionDraftOptions,
|
|
@@ -41,6 +42,7 @@ function mapNewSessionDraft(
|
|
|
41
42
|
row: Awaited<ReturnType<typeof getNewSessionDraftInTransaction>>,
|
|
42
43
|
): NewSessionDraftValue | null {
|
|
43
44
|
if (!row) return null;
|
|
45
|
+
const selectedProjectChannelId = newSessionDraftSelectedProjectChannelId(row);
|
|
44
46
|
return NewSessionDraft.parse({
|
|
45
47
|
revision: row.revision,
|
|
46
48
|
text: row.text,
|
|
@@ -50,6 +52,7 @@ function mapNewSessionDraft(
|
|
|
50
52
|
model: row.model,
|
|
51
53
|
reasoningEffort: row.reasoningEffort,
|
|
52
54
|
latencyMode: row.latencyMode,
|
|
55
|
+
...(selectedProjectChannelId !== undefined ? { selectedProjectChannelId } : {}),
|
|
53
56
|
options: publicNewSessionDraftOptions(row),
|
|
54
57
|
selectionHistory: newSessionSelectionHistory(row),
|
|
55
58
|
updatedAt: row.updatedAt.toISOString(),
|
|
@@ -264,6 +267,9 @@ export async function saveActorNewSessionDraft(
|
|
|
264
267
|
model: input.model,
|
|
265
268
|
reasoningEffort: input.reasoningEffort,
|
|
266
269
|
latencyMode: input.latencyMode,
|
|
270
|
+
...(input.selectedProjectChannelId !== undefined
|
|
271
|
+
? { selectedProjectChannelId: input.selectedProjectChannelId }
|
|
272
|
+
: {}),
|
|
267
273
|
options: input.options,
|
|
268
274
|
// Only managed people are removed through removeWorkspaceMember().
|
|
269
275
|
// API keys and delegated service actors (for example the first-party
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
GitHubActionPolicyActor,
|
|
3
|
+
GitHubActionPolicyActorState,
|
|
4
|
+
GitHubActionPolicyDecision,
|
|
5
|
+
GitHubActionPolicyEffectiveDecision,
|
|
6
|
+
GitHubActionPolicyGroup,
|
|
7
|
+
} from "@opengeni/contracts";
|
|
8
|
+
import {
|
|
9
|
+
listConnectorActionPolicies,
|
|
10
|
+
resolveConnectorActionPolicy,
|
|
11
|
+
upsertConnectorActionPolicies,
|
|
12
|
+
type ConnectorActionPolicySnapshotEntry,
|
|
13
|
+
type Database,
|
|
14
|
+
} from "@opengeni/db";
|
|
15
|
+
import {
|
|
16
|
+
GITHUB_REST_MCP_APP_SERVER_ID,
|
|
17
|
+
GITHUB_REST_MCP_PERSONAL_SERVER_ID,
|
|
18
|
+
GITHUB_REST_WRITE_TOOL_NAMES,
|
|
19
|
+
} from "@opengeni/runtime/github-rest-mcp";
|
|
20
|
+
|
|
21
|
+
export const GITHUB_ACTION_POLICY_GROUP_TOOL_NAMES = {
|
|
22
|
+
routine: GITHUB_REST_WRITE_TOOL_NAMES.filter(
|
|
23
|
+
(toolName) => toolName !== "pull_request_review_submit" && toolName !== "pull_request_merge",
|
|
24
|
+
),
|
|
25
|
+
review: ["pull_request_review_submit"],
|
|
26
|
+
merge: ["pull_request_merge"],
|
|
27
|
+
} as const satisfies Record<GitHubActionPolicyGroup, readonly string[]>;
|
|
28
|
+
|
|
29
|
+
const groupedToolNames = Object.values(GITHUB_ACTION_POLICY_GROUP_TOOL_NAMES).flat();
|
|
30
|
+
if (
|
|
31
|
+
groupedToolNames.length !== new Set(groupedToolNames).size ||
|
|
32
|
+
GITHUB_REST_WRITE_TOOL_NAMES.some((toolName) => !groupedToolNames.includes(toolName))
|
|
33
|
+
) {
|
|
34
|
+
throw new Error("GitHub action policy groups must cover every write tool exactly once");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type GitHubActionPolicyActorBinding = {
|
|
38
|
+
actor: GitHubActionPolicyActor;
|
|
39
|
+
label: string;
|
|
40
|
+
connectionId: string;
|
|
41
|
+
serverId: typeof GITHUB_REST_MCP_APP_SERVER_ID | typeof GITHUB_REST_MCP_PERSONAL_SERVER_ID;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
function effectiveToolDecision(
|
|
45
|
+
policies: readonly ConnectorActionPolicySnapshotEntry[],
|
|
46
|
+
actor: GitHubActionPolicyActorBinding,
|
|
47
|
+
toolName: string,
|
|
48
|
+
): GitHubActionPolicyDecision {
|
|
49
|
+
const resolved = resolveConnectorActionPolicy(policies, {
|
|
50
|
+
connectionId: actor.connectionId,
|
|
51
|
+
serverId: actor.serverId,
|
|
52
|
+
toolName,
|
|
53
|
+
actionName: toolName,
|
|
54
|
+
});
|
|
55
|
+
// Match connector_write admission: absent policy inherits repository capability.
|
|
56
|
+
// This is a policy projection, not a grant of repository or provider access.
|
|
57
|
+
if (!resolved.managed) return "allow";
|
|
58
|
+
if (resolved.entry) return resolved.entry.policy;
|
|
59
|
+
return resolved.decision;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function effectiveGroupDecision(
|
|
63
|
+
policies: readonly ConnectorActionPolicySnapshotEntry[],
|
|
64
|
+
actor: GitHubActionPolicyActorBinding,
|
|
65
|
+
group: GitHubActionPolicyGroup,
|
|
66
|
+
): GitHubActionPolicyEffectiveDecision {
|
|
67
|
+
const decisions = new Set(
|
|
68
|
+
GITHUB_ACTION_POLICY_GROUP_TOOL_NAMES[group].map((toolName) =>
|
|
69
|
+
effectiveToolDecision(policies, actor, toolName),
|
|
70
|
+
),
|
|
71
|
+
);
|
|
72
|
+
return decisions.size === 1 ? decisions.values().next().value! : "mixed";
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function projectGitHubActionPolicyActor(
|
|
76
|
+
policies: readonly ConnectorActionPolicySnapshotEntry[],
|
|
77
|
+
binding: GitHubActionPolicyActorBinding,
|
|
78
|
+
): GitHubActionPolicyActorState {
|
|
79
|
+
const groups = {
|
|
80
|
+
routine: effectiveGroupDecision(policies, binding, "routine"),
|
|
81
|
+
review: effectiveGroupDecision(policies, binding, "review"),
|
|
82
|
+
merge: effectiveGroupDecision(policies, binding, "merge"),
|
|
83
|
+
};
|
|
84
|
+
return binding.actor.kind === "workspace_app"
|
|
85
|
+
? {
|
|
86
|
+
kind: "workspace_app",
|
|
87
|
+
installationId: binding.actor.installationId,
|
|
88
|
+
label: binding.label,
|
|
89
|
+
groups,
|
|
90
|
+
}
|
|
91
|
+
: {
|
|
92
|
+
kind: "personal",
|
|
93
|
+
connectionId: binding.actor.connectionId,
|
|
94
|
+
label: binding.label,
|
|
95
|
+
groups,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export async function listGitHubActionPolicyActors(
|
|
100
|
+
db: Database,
|
|
101
|
+
input: {
|
|
102
|
+
accountId: string;
|
|
103
|
+
workspaceId: string;
|
|
104
|
+
actors: readonly GitHubActionPolicyActorBinding[];
|
|
105
|
+
},
|
|
106
|
+
): Promise<GitHubActionPolicyActorState[]> {
|
|
107
|
+
const policies = await listConnectorActionPolicies(db, {
|
|
108
|
+
accountId: input.accountId,
|
|
109
|
+
workspaceId: input.workspaceId,
|
|
110
|
+
connectionIds: input.actors.map((actor) => actor.connectionId),
|
|
111
|
+
});
|
|
112
|
+
return input.actors.map((actor) => projectGitHubActionPolicyActor(policies, actor));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export async function updateGitHubActionPolicyGroup(
|
|
116
|
+
db: Database,
|
|
117
|
+
input: {
|
|
118
|
+
accountId: string;
|
|
119
|
+
workspaceId: string;
|
|
120
|
+
subjectId: string;
|
|
121
|
+
actor: GitHubActionPolicyActorBinding;
|
|
122
|
+
group: GitHubActionPolicyGroup;
|
|
123
|
+
decision: GitHubActionPolicyDecision;
|
|
124
|
+
},
|
|
125
|
+
): Promise<GitHubActionPolicyActorState> {
|
|
126
|
+
await upsertConnectorActionPolicies(
|
|
127
|
+
db,
|
|
128
|
+
GITHUB_ACTION_POLICY_GROUP_TOOL_NAMES[input.group].map((toolName) => ({
|
|
129
|
+
accountId: input.accountId,
|
|
130
|
+
workspaceId: input.workspaceId,
|
|
131
|
+
subjectId: input.subjectId,
|
|
132
|
+
connectionId: input.actor.connectionId,
|
|
133
|
+
serverId: input.actor.serverId,
|
|
134
|
+
toolName,
|
|
135
|
+
actionName: toolName,
|
|
136
|
+
policy: input.decision,
|
|
137
|
+
})),
|
|
138
|
+
);
|
|
139
|
+
const policies = await listConnectorActionPolicies(db, {
|
|
140
|
+
accountId: input.accountId,
|
|
141
|
+
workspaceId: input.workspaceId,
|
|
142
|
+
connectionIds: [input.actor.connectionId],
|
|
143
|
+
});
|
|
144
|
+
return projectGitHubActionPolicyActor(policies, input.actor);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function githubAppActionPolicyActor(input: {
|
|
148
|
+
installationId: number;
|
|
149
|
+
accountLogin: string | null;
|
|
150
|
+
}): GitHubActionPolicyActorBinding {
|
|
151
|
+
return {
|
|
152
|
+
actor: { kind: "workspace_app", installationId: input.installationId },
|
|
153
|
+
label: input.accountLogin ? `OpenGeni bot on ${input.accountLogin}` : "OpenGeni bot",
|
|
154
|
+
connectionId: `github-app:${input.installationId}`,
|
|
155
|
+
serverId: GITHUB_REST_MCP_APP_SERVER_ID,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function personalGitHubActionPolicyActor(input: {
|
|
160
|
+
connectionId: string;
|
|
161
|
+
githubLogin: string;
|
|
162
|
+
}): GitHubActionPolicyActorBinding {
|
|
163
|
+
return {
|
|
164
|
+
actor: { kind: "personal", connectionId: input.connectionId },
|
|
165
|
+
label: `@${input.githubLogin}`,
|
|
166
|
+
connectionId: input.connectionId,
|
|
167
|
+
serverId: GITHUB_REST_MCP_PERSONAL_SERVER_ID,
|
|
168
|
+
};
|
|
169
|
+
}
|
package/src/domain/sessions.ts
CHANGED
|
@@ -1715,8 +1715,9 @@ export async function postUserMessageTurn(
|
|
|
1715
1715
|
* `session_create` tool: payload validation, resource/tool/variableSet
|
|
1716
1716
|
* checks, usage limits, session start, and usage recording. `rawPayload` is
|
|
1717
1717
|
* the unparsed request body so absent-vs-empty execution-context fields keep
|
|
1718
|
-
* their meaning: a child inherits
|
|
1719
|
-
* trusted immediate parent
|
|
1718
|
+
* their meaning: a child inherits repositories (never files), tools, and MCP
|
|
1719
|
+
* servers from its trusted immediate parent when omitted; explicit arrays
|
|
1720
|
+
* (including []) win. A
|
|
1720
1721
|
* top-level create with omitted tools applies workspace-default capability MCPs.
|
|
1721
1722
|
*/
|
|
1722
1723
|
export function resolveChildGoalFromAcceptedSnapshot(
|
|
@@ -2102,7 +2103,8 @@ export async function createSessionForRequestWithOutcome(
|
|
|
2102
2103
|
const resources = normalizeResources(
|
|
2103
2104
|
hasOwnProperty(rawPayload, "resources")
|
|
2104
2105
|
? payload.resources
|
|
2105
|
-
: (parentSession?.resources
|
|
2106
|
+
: (parentSession?.resources.filter((resource) => resource.kind === "repository") ??
|
|
2107
|
+
payload.resources),
|
|
2106
2108
|
);
|
|
2107
2109
|
const inheritedOrSubmittedSkills = hasOwnProperty(rawPayload, "skills")
|
|
2108
2110
|
? payload.skills
|
package/src/index.ts
CHANGED
|
@@ -80,6 +80,7 @@ export * from "./domain/product-integration-pack";
|
|
|
80
80
|
export * from "./domain/personal-connection-delegations";
|
|
81
81
|
export * from "./domain/resources";
|
|
82
82
|
export * from "./domain/github-repository-bindings";
|
|
83
|
+
export * from "./domain/github-action-policies";
|
|
83
84
|
export * from "./domain/session-tool-policy";
|
|
84
85
|
export * from "./domain/scheduled-tasks";
|
|
85
86
|
export * from "./domain/sessions";
|