@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/core",
3
- "version": "2.7.5-canary.0",
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.0",
58
- "@opengeni/codex": "^0.2.21-canary.0",
59
- "@opengeni/config": "^1.0.0-canary.0",
60
- "@opengeni/contracts": "^2.13.0-canary.0",
61
- "@opengeni/db": "^4.0.0-canary.0",
62
- "@opengeni/documents": "^0.8.19-canary.0",
63
- "@opengeni/events": "^0.4.17-canary.0",
64
- "@opengeni/network": "^0.3.0-canary.0",
65
- "@opengeni/observability": "^0.8.19-canary.0",
66
- "@opengeni/runtime": "^2.3.0-canary.0",
67
- "@opengeni/storage": "^0.2.120-canary.0",
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
+ }
@@ -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 omitted resources/tools/mcpServers from its
1719
- * trusted immediate parent, while explicit arrays (including []) win. A
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 ?? payload.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";