@stackbilt/aegis-core 0.1.0

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 (148) hide show
  1. package/package.json +96 -0
  2. package/schema.sql +586 -0
  3. package/src/adapters/voice/cloudflare-agent.ts +34 -0
  4. package/src/auth.ts +124 -0
  5. package/src/bluesky.ts +464 -0
  6. package/src/claude-tools/content.ts +188 -0
  7. package/src/claude-tools/email.ts +69 -0
  8. package/src/claude-tools/github.ts +440 -0
  9. package/src/claude-tools/goals.ts +116 -0
  10. package/src/claude-tools/index.ts +353 -0
  11. package/src/claude-tools/web.ts +59 -0
  12. package/src/claude.ts +406 -0
  13. package/src/codebeast.ts +200 -0
  14. package/src/composite.ts +715 -0
  15. package/src/content/column.ts +80 -0
  16. package/src/content/hero-image.ts +47 -0
  17. package/src/content/index.ts +27 -0
  18. package/src/content/journal.ts +91 -0
  19. package/src/content/roundtable.ts +163 -0
  20. package/src/core.ts +309 -0
  21. package/src/dashboard.ts +620 -0
  22. package/src/decision-docs.ts +284 -0
  23. package/src/dispatch.ts +13 -0
  24. package/src/edge-env.ts +58 -0
  25. package/src/email.ts +850 -0
  26. package/src/exports.ts +156 -0
  27. package/src/github-projects.ts +312 -0
  28. package/src/github.ts +670 -0
  29. package/src/groq.ts +247 -0
  30. package/src/health-page.ts +578 -0
  31. package/src/index.ts +89 -0
  32. package/src/kernel/argus-actions.ts +397 -0
  33. package/src/kernel/argus-correlation.ts +639 -0
  34. package/src/kernel/board.ts +91 -0
  35. package/src/kernel/briefing.ts +177 -0
  36. package/src/kernel/classify-memory-topic.ts +166 -0
  37. package/src/kernel/cognition.ts +377 -0
  38. package/src/kernel/court-cards.ts +163 -0
  39. package/src/kernel/dispatch.ts +587 -0
  40. package/src/kernel/domain.ts +50 -0
  41. package/src/kernel/dynamic-tools.ts +322 -0
  42. package/src/kernel/executor-port.ts +45 -0
  43. package/src/kernel/executors/claude.ts +73 -0
  44. package/src/kernel/executors/direct.ts +237 -0
  45. package/src/kernel/executors/groq.ts +18 -0
  46. package/src/kernel/executors/index.ts +87 -0
  47. package/src/kernel/executors/tarotscript.ts +104 -0
  48. package/src/kernel/executors/workers-ai.ts +54 -0
  49. package/src/kernel/insight-cache.ts +76 -0
  50. package/src/kernel/memory/agenda.ts +200 -0
  51. package/src/kernel/memory/blocks.ts +188 -0
  52. package/src/kernel/memory/consolidation.ts +194 -0
  53. package/src/kernel/memory/episodic.ts +241 -0
  54. package/src/kernel/memory/goals.ts +156 -0
  55. package/src/kernel/memory/graph.ts +290 -0
  56. package/src/kernel/memory/index.ts +11 -0
  57. package/src/kernel/memory/insights.ts +316 -0
  58. package/src/kernel/memory/procedural.ts +467 -0
  59. package/src/kernel/memory/pruning.ts +67 -0
  60. package/src/kernel/memory/recall.ts +367 -0
  61. package/src/kernel/memory/semantic.ts +315 -0
  62. package/src/kernel/memory/synthesis.ts +161 -0
  63. package/src/kernel/memory-adapter.ts +369 -0
  64. package/src/kernel/memory-guardrails.ts +76 -0
  65. package/src/kernel/port.ts +23 -0
  66. package/src/kernel/resilience.ts +322 -0
  67. package/src/kernel/router.ts +471 -0
  68. package/src/kernel/scheduled/agent-dispatch.ts +252 -0
  69. package/src/kernel/scheduled/argus-analytics.ts +247 -0
  70. package/src/kernel/scheduled/argus-heartbeat.ts +320 -0
  71. package/src/kernel/scheduled/argus-notify.ts +348 -0
  72. package/src/kernel/scheduled/board-sync.ts +110 -0
  73. package/src/kernel/scheduled/ci-watcher.ts +125 -0
  74. package/src/kernel/scheduled/cognitive-metrics.ts +377 -0
  75. package/src/kernel/scheduled/consolidation.ts +229 -0
  76. package/src/kernel/scheduled/content-drip.ts +47 -0
  77. package/src/kernel/scheduled/content.ts +6 -0
  78. package/src/kernel/scheduled/conversation-facts.ts +204 -0
  79. package/src/kernel/scheduled/cost-report.ts +84 -0
  80. package/src/kernel/scheduled/curiosity.ts +219 -0
  81. package/src/kernel/scheduled/dev-activity.ts +44 -0
  82. package/src/kernel/scheduled/digest.ts +317 -0
  83. package/src/kernel/scheduled/dreaming/agenda-triage.ts +115 -0
  84. package/src/kernel/scheduled/dreaming/facts.ts +239 -0
  85. package/src/kernel/scheduled/dreaming/index.ts +8 -0
  86. package/src/kernel/scheduled/dreaming/llm.ts +33 -0
  87. package/src/kernel/scheduled/dreaming/pattern-synthesis.ts +124 -0
  88. package/src/kernel/scheduled/dreaming/persona.ts +75 -0
  89. package/src/kernel/scheduled/dreaming/symbolic.ts +31 -0
  90. package/src/kernel/scheduled/dreaming/task-proposals.ts +80 -0
  91. package/src/kernel/scheduled/dreaming.ts +66 -0
  92. package/src/kernel/scheduled/entropy.ts +149 -0
  93. package/src/kernel/scheduled/escalation.ts +192 -0
  94. package/src/kernel/scheduled/feed-watcher.ts +206 -0
  95. package/src/kernel/scheduled/goals.ts +214 -0
  96. package/src/kernel/scheduled/governance.ts +41 -0
  97. package/src/kernel/scheduled/heartbeat.ts +220 -0
  98. package/src/kernel/scheduled/inbox-processor.ts +174 -0
  99. package/src/kernel/scheduled/index.ts +245 -0
  100. package/src/kernel/scheduled/issue-proposer.ts +478 -0
  101. package/src/kernel/scheduled/issue-watcher.ts +128 -0
  102. package/src/kernel/scheduled/pr-automerge.ts +213 -0
  103. package/src/kernel/scheduled/product-health.ts +107 -0
  104. package/src/kernel/scheduled/reflection.ts +373 -0
  105. package/src/kernel/scheduled/self-improvement.ts +114 -0
  106. package/src/kernel/scheduled/social-engage.ts +175 -0
  107. package/src/kernel/scheduled/task-audit.ts +60 -0
  108. package/src/kernel/symbolic.ts +156 -0
  109. package/src/kernel/types.ts +145 -0
  110. package/src/landing.ts +1190 -0
  111. package/src/lib/audit-chain/chain.ts +28 -0
  112. package/src/lib/audit-chain/types.ts +12 -0
  113. package/src/lib/observability/errors.ts +55 -0
  114. package/src/markdown.ts +164 -0
  115. package/src/mcp/handlers.ts +647 -0
  116. package/src/mcp/server.ts +184 -0
  117. package/src/mcp/tools.ts +316 -0
  118. package/src/mcp-client.ts +275 -0
  119. package/src/mcp-server.ts +2 -0
  120. package/src/operator/config.example.ts +60 -0
  121. package/src/operator/config.ts +60 -0
  122. package/src/operator/index.ts +46 -0
  123. package/src/operator/persona.example.ts +34 -0
  124. package/src/operator/persona.ts +34 -0
  125. package/src/operator/prompt-builder.ts +190 -0
  126. package/src/operator/types.ts +43 -0
  127. package/src/pulse.ts +1179 -0
  128. package/src/routes/bluesky.ts +116 -0
  129. package/src/routes/cc-tasks.ts +328 -0
  130. package/src/routes/codebeast.ts +1 -0
  131. package/src/routes/content.ts +194 -0
  132. package/src/routes/conversations.ts +25 -0
  133. package/src/routes/dynamic-tools.ts +111 -0
  134. package/src/routes/feedback.ts +192 -0
  135. package/src/routes/health.ts +147 -0
  136. package/src/routes/messages.ts +228 -0
  137. package/src/routes/observability.ts +82 -0
  138. package/src/routes/operator-logs.ts +42 -0
  139. package/src/routes/pages.ts +96 -0
  140. package/src/routes/sessions.ts +54 -0
  141. package/src/sanitize.ts +73 -0
  142. package/src/schema-enums.ts +155 -0
  143. package/src/search.ts +112 -0
  144. package/src/task-intelligence.ts +497 -0
  145. package/src/types.ts +194 -0
  146. package/src/ui.ts +5 -0
  147. package/src/version.ts +3 -0
  148. package/src/workers-ai-chat.ts +333 -0
package/src/exports.ts ADDED
@@ -0,0 +1,156 @@
1
+ /**
2
+ * @stackbilt/aegis-core — Main barrel export.
3
+ *
4
+ * This is the primary entry point for consumers who install
5
+ * aegis-core as a dependency. It re-exports the extension
6
+ * interfaces, factory function, and core subsystem modules.
7
+ *
8
+ * Usage:
9
+ * import { createAegisApp, dispatch } from '@stackbilt/aegis-core';
10
+ *
11
+ * For deeper imports, use subpath exports:
12
+ * import { recordMemory } from '@stackbilt/aegis-core/kernel/memory';
13
+ * import { buildEdgeEnv } from '@stackbilt/aegis-core/edge-env';
14
+ */
15
+
16
+ // ─── Factory + Extension Contracts ──────────────────────────
17
+ export {
18
+ createAegisApp,
19
+ type AegisApp,
20
+ type AegisAppConfig,
21
+ type ScheduledTaskPlugin,
22
+ type TaskPhase,
23
+ type ExecutorPlugin,
24
+ type ExecutorResult,
25
+ type RoutePlugin,
26
+ type McpToolPlugin,
27
+ type McpToolDefinition,
28
+ } from './core.js';
29
+
30
+ // ─── Core Types ─────────────────────────────────────────────
31
+ export type {
32
+ // Worker bindings
33
+ Env,
34
+ MemoryServiceBinding,
35
+ MemoryStoreRequest,
36
+ MemoryStoreResult,
37
+ MemoryRecallQuery,
38
+ MemoryFragmentResult,
39
+ MemoryForgetFilter,
40
+ MemoryStatsResult,
41
+ MessageMetadata,
42
+ } from './types.js';
43
+
44
+ export type {
45
+ // Kernel types
46
+ EdgeEnv,
47
+ } from './kernel/dispatch.js';
48
+
49
+ export type {
50
+ KernelIntent,
51
+ DispatchResult,
52
+ Executor,
53
+ ExecutionPlan,
54
+ CognitiveState,
55
+ Channel,
56
+ EpisodicEntry,
57
+ ProceduralEntry,
58
+ ProceduralStatus,
59
+ MemoryEntry,
60
+ Refinement,
61
+ } from './kernel/types.js';
62
+
63
+ export type {
64
+ OperatorConfig,
65
+ Product,
66
+ SelfModel,
67
+ } from './operator/types.js';
68
+
69
+ // ─── Dispatch ───────────────────────────────────────────────
70
+ export {
71
+ dispatch,
72
+ dispatchStream,
73
+ createIntent,
74
+ } from './kernel/dispatch.js';
75
+
76
+ // ─── Memory ─────────────────────────────────────────────────
77
+ export {
78
+ // Episodic
79
+ recordEpisode,
80
+ getEpisodeStats,
81
+ getConversationHistory,
82
+ budgetConversationHistory,
83
+ // Procedural
84
+ getProcedure,
85
+ getAllProcedures,
86
+ upsertProcedure,
87
+ addRefinement,
88
+ degradeProcedure,
89
+ procedureKey,
90
+ // Semantic
91
+ recordMemory,
92
+ searchMemoryByKeywords,
93
+ recallMemory,
94
+ getAllMemoryForContext,
95
+ // Consolidation
96
+ consolidateEpisodicToSemantic,
97
+ // Pruning
98
+ pruneMemory,
99
+ // Insights
100
+ publishInsight,
101
+ validateInsight,
102
+ promoteInsight,
103
+ // Agenda
104
+ getActiveAgendaItems,
105
+ addAgendaItem,
106
+ resolveAgendaItem,
107
+ getAgendaContext,
108
+ // Goals
109
+ getActiveGoals,
110
+ addGoal,
111
+ updateGoalStatus,
112
+ recordGoalAction,
113
+ // Graph
114
+ extractNodes,
115
+ createEdges,
116
+ activateGraph,
117
+ } from './kernel/memory/index.js';
118
+
119
+ // ─── Executors ──────────────────────────────────────────────
120
+ export {
121
+ executeClaude,
122
+ executeClaudeOpus,
123
+ executeClaudeStream,
124
+ executeGroq,
125
+ executeWorkersAi,
126
+ executeGptOss,
127
+ executeDirect,
128
+ executeCodeTask,
129
+ executeTarotScript,
130
+ executeWithAnthropicFailover,
131
+ buildMcpRegistry,
132
+ } from './kernel/executors/index.js';
133
+
134
+ // ─── Scheduled Tasks ────────────────────────────────────────
135
+ export { runScheduledTasks } from './kernel/scheduled/index.js';
136
+
137
+ // ─── Operator ───────────────────────────────────────────────
138
+ export { operatorConfig, setOperatorConfig, renderTemplate } from './operator/index.js';
139
+
140
+ // ─── Auth ───────────────────────────────────────────────────
141
+ export { bearerAuth } from './auth.js';
142
+
143
+ // ─── Edge Env ───────────────────────────────────────────────
144
+ export { buildEdgeEnv } from './edge-env.js';
145
+
146
+ // ─── MCP ────────────────────────────────────────────────────
147
+ export { handleMcpRequest } from './mcp-server.js';
148
+
149
+ // ─── Router ─────────────────────────────────────────────────
150
+ export { route } from './kernel/router.js';
151
+
152
+ // ─── Version ────────────────────────────────────────────────
153
+ export { VERSION } from './version.js';
154
+
155
+ // ─── Observability ──────────────────────────────────────────
156
+ export { InMemoryErrorTracker } from './lib/observability/errors.js';
@@ -0,0 +1,312 @@
1
+ // GitHub Projects v2 -- GraphQL API
2
+ // Separate from github.ts (REST) because GraphQL has fundamentally
3
+ // different request patterns (single endpoint, query strings, variables).
4
+
5
+ const GITHUB_GRAPHQL = 'https://api.github.com/graphql';
6
+ const RETRY_STATUSES = new Set([500, 502, 503]);
7
+ const MAX_RETRIES = 2;
8
+ const RETRY_BASE_MS = 500;
9
+
10
+ // --- Types ---
11
+
12
+ export interface ProjectField {
13
+ id: string;
14
+ name: string;
15
+ options?: { id: string; name: string }[];
16
+ }
17
+
18
+ export interface ProjectItem {
19
+ id: string;
20
+ content: {
21
+ __typename: string;
22
+ number: number;
23
+ title: string;
24
+ state: string;
25
+ repository: { nameWithOwner: string };
26
+ labels: { nodes: { name: string }[] };
27
+ assignees: { nodes: { login: string }[] };
28
+ } | null;
29
+ fieldValues: {
30
+ nodes: { field?: { name: string }; name?: string }[];
31
+ };
32
+ }
33
+
34
+ export interface BoardStatus {
35
+ backlog: string; // option ID
36
+ queued: string;
37
+ in_progress: string;
38
+ blocked: string;
39
+ shipped: string;
40
+ }
41
+
42
+ // --- Core GraphQL fetch ---
43
+
44
+ export async function ghGraphQL<T = unknown>(
45
+ token: string,
46
+ query: string,
47
+ variables: Record<string, unknown> = {},
48
+ ): Promise<T> {
49
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
50
+ const res = await fetch(GITHUB_GRAPHQL, {
51
+ method: 'POST',
52
+ headers: {
53
+ Authorization: `Bearer ${token}`,
54
+ 'Content-Type': 'application/json',
55
+ 'User-Agent': 'aegis-worker/1.0',
56
+ },
57
+ body: JSON.stringify({ query, variables }),
58
+ });
59
+
60
+ // Rate limit
61
+ if (res.status === 403 || res.status === 429) {
62
+ const body = await res.text();
63
+ throw new Error(`GitHub GraphQL ${res.status}: ${body}`);
64
+ }
65
+
66
+ // Transient server errors
67
+ if (RETRY_STATUSES.has(res.status) && attempt < MAX_RETRIES) {
68
+ const delayMs = RETRY_BASE_MS * Math.pow(2, attempt);
69
+ console.warn(`[github-projects] ${res.status}, retrying in ${delayMs}ms`);
70
+ await new Promise(r => setTimeout(r, delayMs));
71
+ continue;
72
+ }
73
+
74
+ if (!res.ok) {
75
+ const body = await res.text();
76
+ throw new Error(`GitHub GraphQL ${res.status}: ${body}`);
77
+ }
78
+
79
+ const json = (await res.json()) as { data?: T; errors?: { message: string }[] };
80
+ if (json.errors?.length) {
81
+ throw new Error(`GitHub GraphQL errors: ${json.errors.map(e => e.message).join('; ')}`);
82
+ }
83
+ return json.data as T;
84
+ }
85
+
86
+ throw new Error('GitHub GraphQL: exhausted retries');
87
+ }
88
+
89
+ // --- Project Discovery ---
90
+
91
+ /** Find an existing org-level project by title, or create one. */
92
+ export async function findOrCreateProject(
93
+ token: string,
94
+ orgLogin: string,
95
+ title: string,
96
+ ): Promise<string> {
97
+ // Search existing projects
98
+ const searchData = await ghGraphQL<{
99
+ organization: {
100
+ projectsV2: { nodes: { id: string; title: string }[] };
101
+ };
102
+ }>(token, `
103
+ query($org: String!, $search: String!) {
104
+ organization(login: $org) {
105
+ projectsV2(first: 20, query: $search) {
106
+ nodes { id title }
107
+ }
108
+ }
109
+ }
110
+ `, { org: orgLogin, search: title });
111
+
112
+ const existing = searchData.organization.projectsV2.nodes.find(p => p.title === title);
113
+ if (existing) return existing.id;
114
+
115
+ // Create new project — first get org node ID
116
+ const orgData = await ghGraphQL<{
117
+ organization: { id: string };
118
+ }>(token, `
119
+ query($org: String!) {
120
+ organization(login: $org) { id }
121
+ }
122
+ `, { org: orgLogin });
123
+
124
+ const createData = await ghGraphQL<{
125
+ createProjectV2: { projectV2: { id: string } };
126
+ }>(token, `
127
+ mutation($ownerId: ID!, $title: String!) {
128
+ createProjectV2(input: { ownerId: $ownerId, title: $title }) {
129
+ projectV2 { id }
130
+ }
131
+ }
132
+ `, { ownerId: orgData.organization.id, title });
133
+
134
+ return createData.createProjectV2.projectV2.id;
135
+ }
136
+
137
+ // --- Field Management ---
138
+
139
+ /** Get the Status field and its option IDs. */
140
+ export async function getStatusField(
141
+ token: string,
142
+ projectId: string,
143
+ ): Promise<{ fieldId: string; options: BoardStatus } | null> {
144
+ const data = await ghGraphQL<{
145
+ node: {
146
+ fields: {
147
+ nodes: {
148
+ __typename: string;
149
+ id: string;
150
+ name: string;
151
+ options?: { id: string; name: string }[];
152
+ }[];
153
+ };
154
+ };
155
+ }>(token, `
156
+ query($projectId: ID!) {
157
+ node(id: $projectId) {
158
+ ... on ProjectV2 {
159
+ fields(first: 20) {
160
+ nodes {
161
+ ... on ProjectV2SingleSelectField {
162
+ __typename id name
163
+ options { id name }
164
+ }
165
+ ... on ProjectV2Field {
166
+ __typename id name
167
+ }
168
+ }
169
+ }
170
+ }
171
+ }
172
+ }
173
+ `, { projectId });
174
+
175
+ const statusField = data.node.fields.nodes.find(
176
+ f => f.name === 'Status' && f.__typename === 'ProjectV2SingleSelectField',
177
+ );
178
+ if (!statusField?.options) return null;
179
+
180
+ const findOption = (name: string) => statusField.options!.find(o => o.name === name)?.id ?? '';
181
+ return {
182
+ fieldId: statusField.id,
183
+ options: {
184
+ backlog: findOption('Backlog'),
185
+ queued: findOption('Queued'),
186
+ in_progress: findOption('In Progress'),
187
+ blocked: findOption('Blocked'),
188
+ shipped: findOption('Shipped'),
189
+ },
190
+ };
191
+ }
192
+
193
+ // --- Item Operations ---
194
+
195
+ /** Add an issue or PR to the project board. Returns the project item ID. */
196
+ export async function addItemToProject(
197
+ token: string,
198
+ projectId: string,
199
+ contentNodeId: string,
200
+ ): Promise<string> {
201
+ const data = await ghGraphQL<{
202
+ addProjectV2ItemById: { item: { id: string } };
203
+ }>(token, `
204
+ mutation($projectId: ID!, $contentId: ID!) {
205
+ addProjectV2ItemById(input: { projectId: $projectId, contentId: $contentId }) {
206
+ item { id }
207
+ }
208
+ }
209
+ `, { projectId, contentId: contentNodeId });
210
+
211
+ return data.addProjectV2ItemById.item.id;
212
+ }
213
+
214
+ /** Update the Status field of a project item. */
215
+ export async function updateItemStatus(
216
+ token: string,
217
+ projectId: string,
218
+ itemId: string,
219
+ statusFieldId: string,
220
+ optionId: string,
221
+ ): Promise<void> {
222
+ await ghGraphQL(token, `
223
+ mutation($projectId: ID!, $itemId: ID!, $fieldId: ID!, $optionId: String!) {
224
+ updateProjectV2ItemFieldValue(input: {
225
+ projectId: $projectId
226
+ itemId: $itemId
227
+ fieldId: $fieldId
228
+ value: { singleSelectOptionId: $optionId }
229
+ }) {
230
+ projectV2Item { id }
231
+ }
232
+ }
233
+ `, { projectId, itemId, fieldId: statusFieldId, optionId });
234
+ }
235
+
236
+ /** List project items with pagination. */
237
+ export async function listProjectItems(
238
+ token: string,
239
+ projectId: string,
240
+ cursor?: string,
241
+ ): Promise<{ items: ProjectItem[]; nextCursor: string | null }> {
242
+ const data = await ghGraphQL<{
243
+ node: {
244
+ items: {
245
+ pageInfo: { hasNextPage: boolean; endCursor: string | null };
246
+ nodes: ProjectItem[];
247
+ };
248
+ };
249
+ }>(token, `
250
+ query($projectId: ID!, $cursor: String) {
251
+ node(id: $projectId) {
252
+ ... on ProjectV2 {
253
+ items(first: 50, after: $cursor) {
254
+ pageInfo { hasNextPage endCursor }
255
+ nodes {
256
+ id
257
+ content {
258
+ ... on Issue {
259
+ __typename number title state
260
+ repository { nameWithOwner }
261
+ labels(first: 10) { nodes { name } }
262
+ assignees(first: 3) { nodes { login } }
263
+ }
264
+ ... on PullRequest {
265
+ __typename number title state
266
+ repository { nameWithOwner }
267
+ labels(first: 10) { nodes { name } }
268
+ assignees(first: 3) { nodes { login } }
269
+ }
270
+ }
271
+ fieldValues(first: 10) {
272
+ nodes {
273
+ ... on ProjectV2ItemFieldSingleSelectValue {
274
+ field { ... on ProjectV2SingleSelectField { name } }
275
+ name
276
+ }
277
+ }
278
+ }
279
+ }
280
+ }
281
+ }
282
+ }
283
+ }
284
+ `, { projectId, cursor: cursor ?? null });
285
+
286
+ return {
287
+ items: data.node.items.nodes,
288
+ nextCursor: data.node.items.pageInfo.hasNextPage
289
+ ? data.node.items.pageInfo.endCursor
290
+ : null,
291
+ };
292
+ }
293
+
294
+ /** Get the node ID for an issue (needed to add it to a project). */
295
+ export async function getIssueNodeId(
296
+ token: string,
297
+ repo: string,
298
+ number: number,
299
+ ): Promise<string> {
300
+ const [owner, name] = repo.split('/');
301
+ const data = await ghGraphQL<{
302
+ repository: { issue: { id: string } };
303
+ }>(token, `
304
+ query($owner: String!, $name: String!, $number: Int!) {
305
+ repository(owner: $owner, name: $name) {
306
+ issue(number: $number) { id }
307
+ }
308
+ }
309
+ `, { owner, name, number });
310
+
311
+ return data.repository.issue.id;
312
+ }