@agent-relay/github-primitive 4.0.9

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.
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Multi-tenant pull-request workflow.
3
+ *
4
+ * Cloud's reality: every workspace (AgentWorkforce, MSD, NightCTO, ...)
5
+ * has its own GitHub App installation. The primitive's per-step `config`
6
+ * field lets one workflow route different actions through different
7
+ * Nango connections — no need for one workflow per tenant.
8
+ *
9
+ * The usual cloud pattern:
10
+ *
11
+ * 1. A resolver helper — lives in cloud, NOT in this primitive — maps
12
+ * { workspaceId, repo } -> { connectionId, providerConfigKey }.
13
+ * Recommended signature:
14
+ *
15
+ * githubConfigForRepo({ repo, workspaceId }): Promise<GitHubRuntimeConfig>
16
+ *
17
+ * It reads the workspace_integrations table, picks the row whose
18
+ * provider matches the target repo's app, and returns a ready-to-
19
+ * use config object.
20
+ *
21
+ * 2. Workflow authors call that resolver at step-build time and pass
22
+ * the result as `config` to each `createGitHubStep` call.
23
+ *
24
+ * This example simulates the resolver with a static table so the
25
+ * illustration is self-contained — in production, swap it for the DB
26
+ * lookup.
27
+ *
28
+ * Run:
29
+ * NANGO_SECRET_KEY=... \
30
+ * AGENTWORKFORCE_CONNECTION_ID=... \
31
+ * MSD_CONNECTION_ID=... \
32
+ * npx tsx examples/multi-tenant-pr-workflow.ts
33
+ */
34
+
35
+ import { WorkflowRunner, type RelayYamlConfig } from '@agent-relay/sdk/workflows';
36
+
37
+ import { GitHubStepExecutor, createGitHubStep } from '../src/workflow-step.js';
38
+ import type { GitHubRuntimeConfig, RepositoryRef } from '../src/types.js';
39
+
40
+ // ─── Resolver (stand-in for cloud's real implementation) ───────────────
41
+
42
+ interface TenantConnection {
43
+ workspaceId: string;
44
+ providerConfigKey: string; // 'github-agentworkforce' | 'github-msd' | 'github-nightcto'
45
+ connectionIdEnvVar: string; // env var that carries the Nango connection id
46
+ }
47
+
48
+ // In cloud, this table is the workspace_integrations DB rows joined to
49
+ // the Nango provider registry. Here we keep it inline for illustration.
50
+ const TENANTS: Record<string, TenantConnection> = {
51
+ 'AgentWorkforce/cloud': {
52
+ workspaceId: 'rw_agentworkforce',
53
+ providerConfigKey: 'github-agentworkforce',
54
+ connectionIdEnvVar: 'AGENTWORKFORCE_CONNECTION_ID',
55
+ },
56
+ 'AgentWorkforce/sage': {
57
+ workspaceId: 'rw_agentworkforce',
58
+ providerConfigKey: 'github-agentworkforce',
59
+ connectionIdEnvVar: 'AGENTWORKFORCE_CONNECTION_ID',
60
+ },
61
+ 'msd-ventures/platform': {
62
+ workspaceId: 'rw_msd',
63
+ providerConfigKey: 'github-msd',
64
+ connectionIdEnvVar: 'MSD_CONNECTION_ID',
65
+ },
66
+ };
67
+
68
+ function githubConfigForRepo(opts: {
69
+ repo: string | RepositoryRef;
70
+ /** Workspace scope. Optional — cloud-owned repos default to the shared app. */
71
+ workspaceId?: string;
72
+ }): GitHubRuntimeConfig {
73
+ const repoKey = typeof opts.repo === 'string' ? opts.repo : `${opts.repo.owner}/${opts.repo.repo}`;
74
+ const tenant = TENANTS[repoKey];
75
+
76
+ if (!tenant) {
77
+ throw new Error(
78
+ `No GitHub connection mapped for ${repoKey} — register it in the tenants table or workspace_integrations.`
79
+ );
80
+ }
81
+
82
+ const connectionId = process.env[tenant.connectionIdEnvVar];
83
+ if (!connectionId) {
84
+ throw new Error(`Missing ${tenant.connectionIdEnvVar} — set the Nango connection id for ${repoKey}.`);
85
+ }
86
+
87
+ return {
88
+ runtime: 'auto',
89
+ nango: {
90
+ connectionId,
91
+ providerConfigKey: tenant.providerConfigKey,
92
+ secretKey: process.env.NANGO_SECRET_KEY,
93
+ },
94
+ relayCloud: {
95
+ apiUrl: process.env.RELAY_CLOUD_API_URL,
96
+ accessToken: process.env.RELAY_CLOUD_API_TOKEN,
97
+ workspaceId: opts.workspaceId ?? tenant.workspaceId,
98
+ },
99
+ };
100
+ }
101
+
102
+ // ─── Workflow ────────────────────────────────────────────────────────────
103
+
104
+ const agentworkforceRepo = 'AgentWorkforce/cloud';
105
+ const msdRepo = 'msd-ventures/platform';
106
+
107
+ const executor = new GitHubStepExecutor({ runtime: 'auto' });
108
+
109
+ const config: RelayYamlConfig = {
110
+ version: '1.0',
111
+ name: 'multi-tenant-pr-workflow',
112
+ description:
113
+ 'Open PRs in two tenants — AgentWorkforce/cloud (shared app) and msd-ventures/platform (MSD app) — from one workflow by varying per-step config.',
114
+ swarm: { pattern: 'pipeline' },
115
+ agents: [],
116
+ workflows: [
117
+ {
118
+ name: 'multi-tenant-pr-workflow',
119
+ steps: [
120
+ // ─── Tenant A: AgentWorkforce ───────────────────────────────
121
+ createGitHubStep({
122
+ name: 'inspect-agentworkforce-cloud',
123
+ action: 'getRepo',
124
+ repo: agentworkforceRepo,
125
+ config: githubConfigForRepo({ repo: agentworkforceRepo }),
126
+ output: { mode: 'summary', includeRuntime: true, pretty: true },
127
+ }),
128
+
129
+ createGitHubStep({
130
+ name: 'open-pr-agentworkforce',
131
+ dependsOn: ['inspect-agentworkforce-cloud'],
132
+ action: 'createPR',
133
+ repo: agentworkforceRepo,
134
+ params: {
135
+ // Pretend we prepared this branch in an earlier workflow step
136
+ // (push-branch in the caller workflow).
137
+ head: 'feat/typed-webhook-consumers',
138
+ base: 'main',
139
+ title: 'feat(web): typed webhook-consumer config',
140
+ body: "Routes through AgentWorkforce's github-agentworkforce Nango connection.",
141
+ draft: true,
142
+ },
143
+ config: githubConfigForRepo({ repo: agentworkforceRepo }),
144
+ output: { mode: 'data', format: 'json', path: 'data.html_url' },
145
+ }),
146
+
147
+ // ─── Tenant B: MSD ──────────────────────────────────────────
148
+ // Same workflow, same action verbs, different connection
149
+ // resolved by the per-step `config` field. Runs sequentially
150
+ // here but could run in parallel — tenants are independent.
151
+ createGitHubStep({
152
+ name: 'inspect-msd-platform',
153
+ dependsOn: ['open-pr-agentworkforce'],
154
+ action: 'getRepo',
155
+ repo: msdRepo,
156
+ config: githubConfigForRepo({ repo: msdRepo }),
157
+ output: { mode: 'summary', includeRuntime: true, pretty: true },
158
+ }),
159
+
160
+ createGitHubStep({
161
+ name: 'open-pr-msd',
162
+ dependsOn: ['inspect-msd-platform'],
163
+ action: 'createPR',
164
+ repo: msdRepo,
165
+ params: {
166
+ head: 'integrations/agent-relay-webhook',
167
+ base: 'main',
168
+ title: 'feat: wire up Agent Relay webhook receiver',
169
+ body: "Routes through MSD's github-msd Nango connection — separate GitHub App install.",
170
+ draft: true,
171
+ },
172
+ config: githubConfigForRepo({ repo: msdRepo }),
173
+ output: { mode: 'data', format: 'json', path: 'data.html_url' },
174
+ }),
175
+ ],
176
+ },
177
+ ],
178
+ errorHandling: { strategy: 'fail-fast' },
179
+ };
180
+
181
+ async function main(): Promise<void> {
182
+ console.log('Opening PRs in two tenants via per-step GitHub config overrides:');
183
+ console.log(` ${agentworkforceRepo} → connection ${TENANTS[agentworkforceRepo].providerConfigKey}`);
184
+ console.log(` ${msdRepo} → connection ${TENANTS[msdRepo].providerConfigKey}`);
185
+ console.log();
186
+
187
+ const runner = new WorkflowRunner({
188
+ cwd: process.cwd(),
189
+ executor,
190
+ });
191
+
192
+ const result = await runner.execute(config);
193
+ console.log(`\nWorkflow completed: ${result.status}`);
194
+ }
195
+
196
+ if (process.argv[1] === new URL(import.meta.url).pathname) {
197
+ main().catch((error) => {
198
+ console.error(error instanceof Error ? error.stack : error);
199
+ process.exitCode = 1;
200
+ });
201
+ }
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@agent-relay/github-primitive",
3
+ "version": "4.0.9",
4
+ "description": "GitHub workflow primitive for Agent Relay",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "default": "./dist/index.js"
13
+ },
14
+ "./workflow-step": {
15
+ "types": "./dist/workflow-step.d.ts",
16
+ "import": "./dist/workflow-step.js",
17
+ "default": "./dist/workflow-step.js"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "examples",
23
+ "docs",
24
+ "templates",
25
+ "DESIGN.md",
26
+ "README.md"
27
+ ],
28
+ "scripts": {
29
+ "build": "tsc",
30
+ "clean": "rm -rf dist",
31
+ "test": "vitest run",
32
+ "test:watch": "vitest"
33
+ },
34
+ "dependencies": {
35
+ "@agent-relay/sdk": "4.0.9"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^22.19.3",
39
+ "typescript": "^5.9.3",
40
+ "vitest": "^3.2.4"
41
+ },
42
+ "publishConfig": {
43
+ "access": "public"
44
+ },
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "git+https://github.com/AgentWorkforce/relay.git",
48
+ "directory": "packages/github-primitive"
49
+ }
50
+ }
@@ -0,0 +1,28 @@
1
+ version: '1.0'
2
+ name: github-repository-inspection
3
+ description: Inspect a GitHub repository and read its README.
4
+ swarm:
5
+ pattern: pipeline
6
+ agents: []
7
+ workflows:
8
+ - name: inspect
9
+ steps:
10
+ - name: inspect-repository
11
+ type: integration
12
+ integration: github
13
+ action: getRepo
14
+ params:
15
+ repo: AgentWorkforce/relay
16
+ output: '{"mode":"summary","includeRuntime":true,"pretty":true}'
17
+ - name: read-readme
18
+ type: integration
19
+ integration: github
20
+ action: readFile
21
+ dependsOn:
22
+ - inspect-repository
23
+ params:
24
+ repo: AgentWorkforce/relay
25
+ path: README.md
26
+ output: '{"mode":"data","format":"text"}'
27
+ errorHandling:
28
+ strategy: fail-fast