@ghx-dev/core 0.2.1 → 0.3.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 (29) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +68 -231
  3. package/dist/{chunk-M5PJLKL5.js → chunk-7A73AXLY.js} +104 -14
  4. package/dist/chunk-7A73AXLY.js.map +1 -0
  5. package/dist/{chunk-HEHONZTO.js → chunk-C2KRRSSX.js} +1 -1
  6. package/dist/chunk-C2KRRSSX.js.map +1 -0
  7. package/dist/cli/index.js +23 -29
  8. package/dist/cli/index.js.map +1 -1
  9. package/dist/index.d.ts +168 -1
  10. package/dist/index.js +8 -4
  11. package/dist/index.js.map +1 -1
  12. package/dist/{issue-mutations-OW464JP3.js → issue-mutations-DIWPF3JH.js} +2 -2
  13. package/dist/{issue-queries-ORG3VPK4.js → issue-queries-YQL65J7X.js} +2 -2
  14. package/dist/{pr-mutations-WOTG6FAB.js → pr-mutations-BVHDCAPR.js} +2 -2
  15. package/dist/{pr-queries-6CJJW7BT.js → pr-queries-NUL2UZJB.js} +2 -2
  16. package/dist/{project-QFSCYDDW.js → project-3ZSPVIOC.js} +2 -2
  17. package/dist/{release-33236BBA.js → release-IQCWD655.js} +2 -2
  18. package/dist/{repo-M6DKCWBG.js → repo-JF47JAZG.js} +2 -2
  19. package/package.json +5 -5
  20. package/skills/using-ghx/SKILL.md +24 -4
  21. package/dist/chunk-HEHONZTO.js.map +0 -1
  22. package/dist/chunk-M5PJLKL5.js.map +0 -1
  23. /package/dist/{issue-mutations-OW464JP3.js.map → issue-mutations-DIWPF3JH.js.map} +0 -0
  24. /package/dist/{issue-queries-ORG3VPK4.js.map → issue-queries-YQL65J7X.js.map} +0 -0
  25. /package/dist/{pr-mutations-WOTG6FAB.js.map → pr-mutations-BVHDCAPR.js.map} +0 -0
  26. /package/dist/{pr-queries-6CJJW7BT.js.map → pr-queries-NUL2UZJB.js.map} +0 -0
  27. /package/dist/{project-QFSCYDDW.js.map → project-3ZSPVIOC.js.map} +0 -0
  28. /package/dist/{release-33236BBA.js.map → release-IQCWD655.js.map} +0 -0
  29. /package/dist/{repo-M6DKCWBG.js.map → repo-JF47JAZG.js.map} +0 -0
package/dist/index.d.ts CHANGED
@@ -1,5 +1,17 @@
1
1
  import { DocumentNode } from 'graphql';
2
2
 
3
+ type TokenResolution = {
4
+ token: string;
5
+ source: "env" | "cache" | "gh-cli";
6
+ };
7
+ declare function resolveGithubToken(): Promise<TokenResolution>;
8
+ declare function invalidateTokenCache(): Promise<void>;
9
+
10
+ /**
11
+ * All possible error codes returned in {@link ResultError.code}.
12
+ *
13
+ * Retryable codes: `RATE_LIMIT`, `NETWORK`, `SERVER`.
14
+ */
3
15
  declare const errorCodes: {
4
16
  readonly Auth: "AUTH";
5
17
  readonly NotFound: "NOT_FOUND";
@@ -10,24 +22,49 @@ declare const errorCodes: {
10
22
  readonly AdapterUnsupported: "ADAPTER_UNSUPPORTED";
11
23
  readonly Unknown: "UNKNOWN";
12
24
  };
25
+ /** Union of all error code string literals. */
13
26
  type ErrorCode = (typeof errorCodes)[keyof typeof errorCodes];
14
27
 
28
+ /**
29
+ * All possible reason codes explaining why a particular route was selected.
30
+ *
31
+ * Included in {@link ResultMeta.reason}.
32
+ */
15
33
  declare const routeReasonCodes: readonly ["INPUT_VALIDATION", "OUTPUT_VALIDATION", "CARD_PREFERRED", "CARD_FALLBACK", "PREFLIGHT_FAILED", "ENV_CONSTRAINT", "CAPABILITY_LIMIT", "DEFAULT_POLICY"];
34
+ /** Reason code explaining why a particular route was selected. */
16
35
  type RouteReasonCode = (typeof routeReasonCodes)[number];
17
36
 
37
+ /** The transport route used to execute a capability. */
18
38
  type RouteSource = "cli" | "rest" | "graphql";
39
+ /**
40
+ * Structured error returned inside a {@link ResultEnvelope} when `ok` is `false`.
41
+ *
42
+ * @see {@link ErrorCode} for the full list of error codes.
43
+ */
19
44
  interface ResultError {
20
45
  code: ErrorCode;
21
46
  message: string;
22
47
  retryable: boolean;
23
48
  details?: Record<string, unknown>;
24
49
  }
50
+ /**
51
+ * Records a single route attempt during execution.
52
+ *
53
+ * The routing engine may try multiple routes (preferred → fallback).
54
+ * Each attempt is logged here regardless of outcome.
55
+ */
25
56
  interface AttemptMeta {
26
57
  route: RouteSource;
27
58
  status: "success" | "error" | "skipped";
28
59
  error_code?: ErrorCode;
29
60
  duration_ms?: number;
30
61
  }
62
+ /**
63
+ * Metadata attached to every {@link ResultEnvelope}.
64
+ *
65
+ * Provides observability into which route was used, why, how long it took,
66
+ * and the full list of route attempts.
67
+ */
31
68
  interface ResultMeta {
32
69
  capability_id: string;
33
70
  route_used?: RouteSource;
@@ -47,19 +84,35 @@ interface ResultMeta {
47
84
  tokens_out?: number;
48
85
  };
49
86
  }
87
+ /**
88
+ * The universal response contract for all ghx operations.
89
+ *
90
+ * Every call to {@link executeTask} returns a `ResultEnvelope` — it never throws.
91
+ * Check `ok` to distinguish success from failure; `data` and `error` are exclusive.
92
+ *
93
+ * @typeParam TData - The shape of the success payload, varies per capability.
94
+ */
50
95
  interface ResultEnvelope<TData = unknown> {
51
96
  ok: boolean;
52
97
  data?: TData;
53
98
  error?: ResultError;
54
99
  meta: ResultMeta;
55
100
  }
101
+ /** Aggregate outcome of a batch execution via {@link executeTasks}. */
56
102
  type ChainStatus = "success" | "partial" | "failed";
103
+ /** Result of a single step within a chain execution. */
57
104
  interface ChainStepResult {
58
105
  task: string;
59
106
  ok: boolean;
60
107
  data?: unknown;
61
108
  error?: ResultError;
62
109
  }
110
+ /**
111
+ * Response envelope for batch operations via {@link executeTasks}.
112
+ *
113
+ * Contains per-step results and aggregate metadata
114
+ * (total, succeeded, failed counts).
115
+ */
63
116
  interface ChainResultEnvelope {
64
117
  status: ChainStatus;
65
118
  results: ChainStepResult[];
@@ -71,7 +124,13 @@ interface ChainResultEnvelope {
71
124
  };
72
125
  }
73
126
 
127
+ /** A dotted capability identifier (e.g. `"pr.view"`, `"issue.labels.add"`). */
74
128
  type TaskId = string;
129
+ /**
130
+ * A request to execute a single ghx capability.
131
+ *
132
+ * @typeParam TInput - The shape of the input payload, varies per capability.
133
+ */
75
134
  interface TaskRequest<TInput = Record<string, unknown>> {
76
135
  task: TaskId;
77
136
  input: TInput;
@@ -82,13 +141,28 @@ type ExecuteTaskFn = (request: {
82
141
  input: Record<string, unknown>;
83
142
  options?: Record<string, unknown>;
84
143
  }) => Promise<ResultEnvelope>;
144
+ /**
145
+ * Creates an execute tool suitable for wiring into an AI agent's tool loop.
146
+ *
147
+ * Wraps the execution engine into a simple `{ execute(capabilityId, params) }` shape.
148
+ *
149
+ * @example
150
+ * ```ts
151
+ * const tool = createExecuteTool({
152
+ * executeTask: (req) => executeTask(req, deps),
153
+ * })
154
+ * const result = await tool.execute("repo.view", { owner: "aryeko", name: "ghx" })
155
+ * ```
156
+ */
85
157
  declare function createExecuteTool(deps: {
86
158
  executeTask: ExecuteTaskFn;
87
159
  }): {
88
160
  execute(capabilityId: string, params: Record<string, unknown>, options?: Record<string, unknown>): Promise<ResultEnvelope>;
89
161
  };
90
162
 
163
+ /** Represents a JSON Schema definition for card inputs/outputs. */
91
164
  type JsonSchema = Record<string, unknown>;
165
+ /** Defines when a fallback route should override the preferred route. */
92
166
  interface SuitabilityRule {
93
167
  when: "always" | "env" | "params";
94
168
  predicate: string;
@@ -173,16 +247,25 @@ interface NullLiteralInject {
173
247
  target: string;
174
248
  source: "null_literal";
175
249
  }
250
+ /** A specification for how to inject a resolved Phase 1 value into Phase 2. */
176
251
  type InjectSpec = ScalarInject | MapArrayInject | InputPassthroughInject | NullLiteralInject;
252
+ /** Defines the GraphQL query to run during the Phase 1 lookup. */
177
253
  interface LookupSpec {
178
254
  operationName: string;
179
255
  documentPath: string;
180
256
  vars: Record<string, string>;
181
257
  }
258
+ /** Configuration for a Phase 1 node ID lookup prior to mutation execution. */
182
259
  interface ResolutionConfig {
183
260
  lookup: LookupSpec;
184
261
  inject: InjectSpec[];
185
262
  }
263
+ /**
264
+ * Declarative configuration for a single ghx capability.
265
+ *
266
+ * Defines the capability's identity, input/output schemas, routing preferences,
267
+ * and adapter-specific execution details (GraphQL, CLI, REST).
268
+ */
186
269
  interface OperationCard<Input = Record<string, unknown>> {
187
270
  capability_id: string;
188
271
  version: string;
@@ -239,6 +322,7 @@ type SafeRunnerOptions = {
239
322
  };
240
323
  declare function createSafeCliCommandRunner(options?: SafeRunnerOptions): CliCommandRunner;
241
324
 
325
+ /** Structured explanation of a capability, returned by {@link explainCapability}. */
242
326
  type CapabilityExplanation = {
243
327
  capability_id: string;
244
328
  purpose: string;
@@ -248,11 +332,19 @@ type CapabilityExplanation = {
248
332
  fallback_routes: Array<"cli" | "graphql" | "rest">;
249
333
  output_fields: string[];
250
334
  };
335
+ /**
336
+ * Return a structured explanation of a capability by its ID.
337
+ *
338
+ * @throws If the capability ID is unknown.
339
+ */
251
340
  declare function explainCapability(capabilityId: string): CapabilityExplanation;
252
341
 
342
+ /** Return a copy of all registered operation cards, in canonical order. */
253
343
  declare function listOperationCards(): OperationCard[];
344
+ /** Look up a single operation card by its dotted capability ID (e.g. `"pr.view"`). */
254
345
  declare function getOperationCard(capabilityId: string): OperationCard | undefined;
255
346
 
347
+ /** Summary of a capability, returned by {@link listCapabilities}. */
256
348
  type CapabilityListItem = {
257
349
  capability_id: string;
258
350
  description: string;
@@ -260,31 +352,56 @@ type CapabilityListItem = {
260
352
  optional_inputs: string[];
261
353
  optional_inputs_detail: Record<string, unknown>;
262
354
  };
355
+ /**
356
+ * List all available capabilities, optionally filtered by domain.
357
+ *
358
+ * @param domain - Filter by top-level domain (e.g. `"pr"`, `"issue"`, `"workflow"`).
359
+ */
263
360
  declare function listCapabilities(domain?: string): CapabilityListItem[];
264
361
 
265
362
  type GraphqlVariables = Record<string, unknown>;
363
+ /** A single error from a GraphQL response. */
266
364
  type GraphqlError = {
267
365
  message: string;
268
366
  path?: ReadonlyArray<string | number>;
269
367
  extensions?: Record<string, unknown>;
270
368
  };
369
+ /** Raw GraphQL response containing both `data` and `errors` fields. */
271
370
  type GraphqlRawResult<TData> = {
272
371
  data: TData | undefined;
273
372
  errors: GraphqlError[] | undefined;
274
373
  };
275
374
  type GraphqlDocument = string | DocumentNode;
375
+ /**
376
+ * Low-level transport interface for sending GraphQL queries.
377
+ *
378
+ * Implement this to use a custom HTTP client, proxy, or mock.
379
+ * Pass to {@link createGithubClient} or {@link createGraphqlClient}.
380
+ */
276
381
  interface GraphqlTransport {
277
382
  execute<TData>(query: string, variables?: GraphqlVariables): Promise<TData>;
278
383
  executeRaw?<TData>(query: string, variables?: GraphqlVariables): Promise<GraphqlRawResult<TData>>;
279
384
  }
385
+ /**
386
+ * Higher-level GraphQL client with `query` and `queryRaw` methods.
387
+ *
388
+ * Created by {@link createGraphqlClient} from a {@link GraphqlTransport}.
389
+ */
280
390
  interface GraphqlClient {
281
391
  query<TData, TVariables extends GraphqlVariables = GraphqlVariables>(query: GraphqlDocument, variables?: TVariables): Promise<TData>;
282
392
  queryRaw<TData, TVariables extends GraphqlVariables = GraphqlVariables>(query: GraphqlDocument, variables?: TVariables): Promise<GraphqlRawResult<TData>>;
283
393
  }
394
+ /** Options for creating a token-based GraphQL transport. */
284
395
  type TokenClientOptions = {
285
396
  token: string;
286
397
  graphqlUrl?: string;
287
398
  };
399
+ /**
400
+ * Create a {@link GraphqlClient} from a {@link GraphqlTransport}.
401
+ *
402
+ * Wraps the raw transport `execute` method with query string normalization
403
+ * and a `queryRaw` method that returns settled results.
404
+ */
288
405
  declare function createGraphqlClient(transport: GraphqlTransport): GraphqlClient;
289
406
 
290
407
  type Maybe<T> = T | null;
@@ -1013,6 +1130,14 @@ type ProjectV2ItemFieldUpdateData = {
1013
1130
  itemId: string;
1014
1131
  };
1015
1132
 
1133
+ /**
1134
+ * High-level GitHub API client with 50+ typed methods.
1135
+ *
1136
+ * Extends {@link GraphqlClient} with domain-specific helpers for issues, PRs,
1137
+ * releases, projects, and repos. Domain modules are lazy-loaded on first use.
1138
+ *
1139
+ * Create via {@link createGithubClientFromToken} or {@link createGithubClient}.
1140
+ */
1016
1141
  interface GithubClient extends GraphqlClient {
1017
1142
  fetchRepoView(input: RepoViewInput): Promise<RepoViewData>;
1018
1143
  fetchIssueCommentsList(input: IssueCommentsListInput): Promise<IssueCommentsListData>;
@@ -1067,9 +1192,28 @@ interface GithubClient extends GraphqlClient {
1067
1192
  removeProjectV2Item(input: ProjectV2ItemRemoveInput): Promise<ProjectV2ItemRemoveData>;
1068
1193
  updateProjectV2ItemField(input: ProjectV2ItemFieldUpdateInput): Promise<ProjectV2ItemFieldUpdateData>;
1069
1194
  }
1195
+ /**
1196
+ * Create a {@link GithubClient} from a token (string or options object).
1197
+ *
1198
+ * Uses the default `fetch`-based transport. For custom transports, use
1199
+ * {@link createGithubClient} instead.
1200
+ *
1201
+ * @throws If the token is empty.
1202
+ */
1070
1203
  declare function createGithubClientFromToken(tokenOrOptions: string | TokenClientOptions): GithubClient;
1204
+ /**
1205
+ * Create a {@link GithubClient} from a custom {@link GraphqlTransport}.
1206
+ *
1207
+ * Use this for enterprise endpoints, proxies, or test mocking.
1208
+ */
1071
1209
  declare function createGithubClient(transport: GraphqlTransport): GithubClient;
1072
1210
 
1211
+ /**
1212
+ * Cache for Phase 1 resolution lookups in batch execution.
1213
+ *
1214
+ * Avoids redundant GraphQL lookups when the same entity is referenced
1215
+ * by multiple steps in a chain.
1216
+ */
1073
1217
  interface ResolutionCache {
1074
1218
  get(key: string): unknown | undefined;
1075
1219
  set(key: string, value: unknown): void;
@@ -1083,9 +1227,20 @@ interface ResolutionCacheOptions {
1083
1227
  /** Maximum number of cached entries. Default: 200. */
1084
1228
  maxEntries?: number;
1085
1229
  }
1230
+ /**
1231
+ * Create an in-memory resolution cache with TTL and FIFO eviction.
1232
+ *
1233
+ * Pass to `ExecutionDeps.resolutionCache` for batch operations.
1234
+ */
1086
1235
  declare function createResolutionCache(opts?: ResolutionCacheOptions): ResolutionCache;
1236
+ /** Build a deterministic cache key from an operation name and variables. */
1087
1237
  declare function buildCacheKey(operationName: string, variables: Record<string, unknown>): string;
1088
1238
 
1239
+ /**
1240
+ * Dependencies required by the execution engine.
1241
+ *
1242
+ * Pass to {@link executeTask} or {@link executeTasks}.
1243
+ */
1089
1244
  type ExecutionDeps = {
1090
1245
  githubClient: GithubClient;
1091
1246
  githubToken?: string | null;
@@ -1097,10 +1252,22 @@ type ExecutionDeps = {
1097
1252
  resolutionCache?: ResolutionCache;
1098
1253
  };
1099
1254
 
1255
+ /**
1256
+ * Execute a single GitHub operation.
1257
+ *
1258
+ * Looks up the operation card, validates input, selects a route, and returns
1259
+ * a {@link ResultEnvelope}. Never throws.
1260
+ */
1100
1261
  declare function executeTask(request: TaskRequest, deps: ExecutionDeps): Promise<ResultEnvelope>;
1262
+ /**
1263
+ * Execute multiple operations as a batch.
1264
+ *
1265
+ * Classifies steps, resolves node IDs via Phase 1 lookups, batches GraphQL
1266
+ * operations, and returns a {@link ChainResultEnvelope}.
1267
+ */
1101
1268
  declare function executeTasks(requests: Array<{
1102
1269
  task: string;
1103
1270
  input: Record<string, unknown>;
1104
1271
  }>, deps: ExecutionDeps): Promise<ChainResultEnvelope>;
1105
1272
 
1106
- export { type AttemptMeta, type CapabilityExplanation, type CapabilityListItem, type ChainResultEnvelope, type ChainStatus, type ChainStepResult, type CliCommandRunner, type GithubClient, type GraphqlClient, type GraphqlError, type GraphqlRawResult, type GraphqlTransport, type OperationCard, type ResolutionCache, type ResolutionCacheOptions, type ResultEnvelope, type ResultError, type ResultMeta, type RouteReasonCode, type RouteSource, type TaskRequest, type TokenClientOptions, buildCacheKey, createExecuteTool, createGithubClient, createGithubClientFromToken, createGraphqlClient, createResolutionCache, createSafeCliCommandRunner, executeTask, executeTasks, explainCapability, getOperationCard, listCapabilities, listOperationCards };
1273
+ export { type AttemptMeta, type CapabilityExplanation, type CapabilityListItem, type ChainResultEnvelope, type ChainStatus, type ChainStepResult, type CliCommandRunner, type GithubClient, type GraphqlClient, type GraphqlError, type GraphqlRawResult, type GraphqlTransport, type OperationCard, type ResolutionCache, type ResolutionCacheOptions, type ResultEnvelope, type ResultError, type ResultMeta, type RouteReasonCode, type RouteSource, type TaskRequest, type TokenClientOptions, type TokenResolution, buildCacheKey, createExecuteTool, createGithubClient, createGithubClientFromToken, createGraphqlClient, createResolutionCache, createSafeCliCommandRunner, executeTask, executeTasks, explainCapability, getOperationCard, invalidateTokenCache, listCapabilities, listOperationCards, resolveGithubToken };
package/dist/index.js CHANGED
@@ -8,9 +8,11 @@ import {
8
8
  executeTasks,
9
9
  explainCapability,
10
10
  getOperationCard,
11
+ invalidateTokenCache,
11
12
  listCapabilities,
12
- listOperationCards
13
- } from "./chunk-M5PJLKL5.js";
13
+ listOperationCards,
14
+ resolveGithubToken
15
+ } from "./chunk-7A73AXLY.js";
14
16
  import "./chunk-H7CLZHRO.js";
15
17
  import "./chunk-NQ53ETYV.js";
16
18
  import "./chunk-TGL33GEA.js";
@@ -24,7 +26,7 @@ import "./chunk-GQO6BHJV.js";
24
26
  import "./chunk-R3CBGJZX.js";
25
27
  import {
26
28
  createGraphqlClient
27
- } from "./chunk-HEHONZTO.js";
29
+ } from "./chunk-C2KRRSSX.js";
28
30
 
29
31
  // src/core/execute/execute-tool.ts
30
32
  function createExecuteTool(deps) {
@@ -51,7 +53,9 @@ export {
51
53
  executeTasks,
52
54
  explainCapability,
53
55
  getOperationCard,
56
+ invalidateTokenCache,
54
57
  listCapabilities,
55
- listOperationCards
58
+ listOperationCards,
59
+ resolveGithubToken
56
60
  };
57
61
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/execute/execute-tool.ts"],"sourcesContent":["import type { ResultEnvelope } from \"../contracts/envelope.js\"\n\ntype ExecuteTaskFn = (request: {\n task: string\n input: Record<string, unknown>\n options?: Record<string, unknown>\n}) => Promise<ResultEnvelope>\n\nexport function createExecuteTool(deps: { executeTask: ExecuteTaskFn }) {\n return {\n execute(\n capabilityId: string,\n params: Record<string, unknown>,\n options?: Record<string, unknown>,\n ): Promise<ResultEnvelope> {\n const request = {\n task: capabilityId,\n input: params,\n ...(options ? { options } : {}),\n }\n\n return deps.executeTask(request)\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQO,SAAS,kBAAkB,MAAsC;AACtE,SAAO;AAAA,IACL,QACE,cACA,QACA,SACyB;AACzB,YAAM,UAAU;AAAA,QACd,MAAM;AAAA,QACN,OAAO;AAAA,QACP,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,MAC/B;AAEA,aAAO,KAAK,YAAY,OAAO;AAAA,IACjC;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/core/execute/execute-tool.ts"],"sourcesContent":["import type { ResultEnvelope } from \"../contracts/envelope.js\"\n\ntype ExecuteTaskFn = (request: {\n task: string\n input: Record<string, unknown>\n options?: Record<string, unknown>\n}) => Promise<ResultEnvelope>\n\n/**\n * Creates an execute tool suitable for wiring into an AI agent's tool loop.\n *\n * Wraps the execution engine into a simple `{ execute(capabilityId, params) }` shape.\n *\n * @example\n * ```ts\n * const tool = createExecuteTool({\n * executeTask: (req) => executeTask(req, deps),\n * })\n * const result = await tool.execute(\"repo.view\", { owner: \"aryeko\", name: \"ghx\" })\n * ```\n */\nexport function createExecuteTool(deps: { executeTask: ExecuteTaskFn }) {\n return {\n execute(\n capabilityId: string,\n params: Record<string, unknown>,\n options?: Record<string, unknown>,\n ): Promise<ResultEnvelope> {\n const request = {\n task: capabilityId,\n input: params,\n ...(options ? { options } : {}),\n }\n\n return deps.executeTask(request)\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqBO,SAAS,kBAAkB,MAAsC;AACtE,SAAO;AAAA,IACL,QACE,cACA,QACA,SACyB;AACzB,YAAM,UAAU;AAAA,QACd,MAAM;AAAA,QACN,OAAO;AAAA,QACP,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,MAC/B;AAEA,aAAO,KAAK,YAAY,OAAO;AAAA,IACjC;AAAA,EACF;AACF;","names":[]}
@@ -51,7 +51,7 @@ import {
51
51
  } from "./chunk-OQWLEFAH.js";
52
52
  import {
53
53
  createGraphqlRequestClient
54
- } from "./chunk-HEHONZTO.js";
54
+ } from "./chunk-C2KRRSSX.js";
55
55
 
56
56
  // src/gql/domains/issue-mutations.ts
57
57
  function parseIssueNode(issue) {
@@ -642,4 +642,4 @@ export {
642
642
  runIssueReopen,
643
643
  runIssueUpdate
644
644
  };
645
- //# sourceMappingURL=issue-mutations-OW464JP3.js.map
645
+ //# sourceMappingURL=issue-mutations-DIWPF3JH.js.map
@@ -12,7 +12,7 @@ import {
12
12
  } from "./chunk-OQWLEFAH.js";
13
13
  import {
14
14
  createGraphqlRequestClient
15
- } from "./chunk-HEHONZTO.js";
15
+ } from "./chunk-C2KRRSSX.js";
16
16
 
17
17
  // src/gql/domains/issue-queries.ts
18
18
  async function runIssueView(transport, input) {
@@ -90,4 +90,4 @@ export {
90
90
  runIssueList,
91
91
  runIssueView
92
92
  };
93
- //# sourceMappingURL=issue-queries-ORG3VPK4.js.map
93
+ //# sourceMappingURL=issue-queries-YQL65J7X.js.map
@@ -33,7 +33,7 @@ import {
33
33
  } from "./chunk-OQWLEFAH.js";
34
34
  import {
35
35
  createGraphqlRequestClient
36
- } from "./chunk-HEHONZTO.js";
36
+ } from "./chunk-C2KRRSSX.js";
37
37
 
38
38
  // src/gql/operations/review-thread-state.generated.ts
39
39
  var ReviewThreadStateDocument = `
@@ -481,4 +481,4 @@ export {
481
481
  runSubmitPrReview,
482
482
  runUnresolveReviewThread
483
483
  };
484
- //# sourceMappingURL=pr-mutations-WOTG6FAB.js.map
484
+ //# sourceMappingURL=pr-mutations-BVHDCAPR.js.map
@@ -15,7 +15,7 @@ import {
15
15
  } from "./chunk-OQWLEFAH.js";
16
16
  import {
17
17
  createGraphqlRequestClient
18
- } from "./chunk-HEHONZTO.js";
18
+ } from "./chunk-C2KRRSSX.js";
19
19
 
20
20
  // src/gql/domains/pr-queries.ts
21
21
  async function runPrView(transport, input) {
@@ -140,4 +140,4 @@ export {
140
140
  runPrReviewsList,
141
141
  runPrView
142
142
  };
143
- //# sourceMappingURL=pr-queries-6CJJW7BT.js.map
143
+ //# sourceMappingURL=pr-queries-NUL2UZJB.js.map
@@ -19,7 +19,7 @@ import {
19
19
  } from "./chunk-OQWLEFAH.js";
20
20
  import {
21
21
  createGraphqlRequestClient
22
- } from "./chunk-HEHONZTO.js";
22
+ } from "./chunk-C2KRRSSX.js";
23
23
 
24
24
  // src/gql/operations/project-v2-fields-list-user.generated.ts
25
25
  var ProjectV2FieldsListUserDocument = `
@@ -426,4 +426,4 @@ export {
426
426
  runProjectV2OrgView,
427
427
  runProjectV2UserView
428
428
  };
429
- //# sourceMappingURL=project-QFSCYDDW.js.map
429
+ //# sourceMappingURL=project-3ZSPVIOC.js.map
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-OQWLEFAH.js";
10
10
  import {
11
11
  createGraphqlRequestClient
12
- } from "./chunk-HEHONZTO.js";
12
+ } from "./chunk-C2KRRSSX.js";
13
13
 
14
14
  // src/gql/domains/release.ts
15
15
  function mapReleaseNode(r) {
@@ -54,4 +54,4 @@ export {
54
54
  runReleaseList,
55
55
  runReleaseView
56
56
  };
57
- //# sourceMappingURL=release-33236BBA.js.map
57
+ //# sourceMappingURL=release-IQCWD655.js.map
@@ -10,7 +10,7 @@ import {
10
10
  } from "./chunk-OQWLEFAH.js";
11
11
  import {
12
12
  createGraphqlRequestClient
13
- } from "./chunk-HEHONZTO.js";
13
+ } from "./chunk-C2KRRSSX.js";
14
14
 
15
15
  // src/gql/domains/repo.ts
16
16
  async function runRepoView(transport, input) {
@@ -79,4 +79,4 @@ export {
79
79
  runRepoLabelsList,
80
80
  runRepoView
81
81
  };
82
- //# sourceMappingURL=repo-M6DKCWBG.js.map
82
+ //# sourceMappingURL=repo-JF47JAZG.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghx-dev/core",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "GitHub execution router for AI agents with deterministic routing and normalized output.",
5
5
  "author": "Arye Kogan",
6
6
  "license": "MIT",
@@ -65,7 +65,7 @@
65
65
  },
66
66
  "dependencies": {
67
67
  "ajv": "^8.18.0",
68
- "graphql": "^16.11.0",
68
+ "graphql": "^16.13.1",
69
69
  "graphql-request": "^7.3.1",
70
70
  "graphql-tag": "^2.12.6",
71
71
  "js-yaml": "^4.1.0"
@@ -77,15 +77,15 @@
77
77
  "@graphql-codegen/typescript": "^5.0.8",
78
78
  "@graphql-codegen/typescript-graphql-request": "^6.3.0",
79
79
  "@graphql-codegen/typescript-operations": "^5.0.8",
80
- "@opencode-ai/sdk": "^1.2.10",
80
+ "@opencode-ai/sdk": "^1.2.23",
81
81
  "@types/js-yaml": "^4.0.9",
82
82
  "@types/node": "^25.2.3",
83
- "@vitest/coverage-v8": "^2.1.8",
83
+ "@vitest/coverage-v8": "^3.2.4",
84
84
  "tsup": "^8.5.0",
85
85
  "tsx": "^4.21.0",
86
86
  "typescript": "^5.9.3",
87
87
  "vite-tsconfig-paths": "^6.1.1",
88
- "vitest": "^2.1.8"
88
+ "vitest": "^3.2.4"
89
89
  },
90
90
  "scripts": {
91
91
  "ghx": "tsx src/cli/index.ts",
@@ -1,10 +1,19 @@
1
1
  ---
2
- description: Execute GitHub operations via ghx — deterministic routing, normalized output, 70 capabilities
2
+ name: using-ghx
3
+ description: Executes GitHub operations via ghx. Use for all GitHub interactions instead of raw gh or gh api commands.
3
4
  ---
4
5
 
5
6
  # ghx CLI Skill
6
7
 
7
- **CRITICAL:** Use `ghx` for ALL GitHub operations. Do not use `gh api` or any other raw `gh` commands unless no matching ghx capability exists.
8
+ ## Authentication
9
+
10
+ ghx automatically resolves your GitHub token. It checks (in order):
11
+ 1. `GITHUB_TOKEN` environment variable
12
+ 2. `GH_TOKEN` environment variable
13
+ 3. Cached token (from previous resolution)
14
+ 4. `gh auth token` (requires `gh` CLI authenticated via `gh auth login`)
15
+
16
+ If you are authenticated via `gh auth login`, ghx works out of the box with no extra configuration.
8
17
 
9
18
  ## Capabilities
10
19
 
@@ -103,7 +112,16 @@ Example (submitting a review with inline comments):
103
112
 
104
113
  ```bash
105
114
  ghx run pr.reviews.submit --input - <<'EOF'
106
- {"owner": "acme", "name": "my-repo", "prNumber": 42, "event": "REQUEST_CHANGES", "body": "Please fix the issues.", "comments": [{"path": "src/index.ts", "line": 10, "body": "Off-by-one error here."}]}
115
+ {
116
+ "owner": "acme",
117
+ "name": "my-repo",
118
+ "prNumber": 42,
119
+ "event": "REQUEST_CHANGES",
120
+ "body": "Please fix the issues.",
121
+ "comments": [
122
+ { "path": "src/index.ts", "line": 10, "body": "Off-by-one error here." }
123
+ ]
124
+ }
107
125
  EOF
108
126
  ```
109
127
 
@@ -111,7 +129,7 @@ EOF
111
129
 
112
130
  ## Chain
113
131
 
114
- **Always use `ghx chain` when you have two or more operations to execute in a single call.** It batches steps into as few GraphQL round-trips as possible (typically one) — reducing latency and avoiding mid-sequence failures. Steps are not transactional; a `"partial"` result is possible if one step fails after another has already succeeded.
132
+ Use `ghx chain` when you have two or more operations to run. It batches steps into as few GraphQL round-trips as possible (typically one) — reducing latency and avoiding mid-sequence failures. Steps are not transactional; a `"partial"` result is possible if one step fails after another has already succeeded.
115
133
 
116
134
  ```bash
117
135
  ghx chain --steps - <<'EOF'
@@ -125,3 +143,5 @@ EOF
125
143
  **Result:** `{ status, results[] }`. Each result: `{ task, ok, data? }` on success — `{ task, ok, error: { code, message } }` on failure.
126
144
 
127
145
  **CRITICAL:** Do not use `gh api` or any other raw `gh` commands unless no matching ghx capability exists. Always try `ghx` first.
146
+
147
+ **IMPORTANT:** Always use `ghx chain` when you have two or more operations to execute in a single call!
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/gql/transport.ts"],"sourcesContent":["import { type DocumentNode, print } from \"graphql\"\nimport type { GraphQLClient, RequestDocument, RequestOptions } from \"graphql-request\"\n\nexport type GraphqlVariables = Record<string, unknown>\n\nexport type GraphqlError = {\n message: string\n path?: ReadonlyArray<string | number>\n extensions?: Record<string, unknown>\n}\n\nexport type GraphqlRawResult<TData> = {\n data: TData | undefined\n errors: GraphqlError[] | undefined\n}\n\ntype GraphqlDocument = string | DocumentNode\ntype QueryLike = GraphqlDocument | RequestDocument\n\nexport interface GraphqlTransport {\n execute<TData>(query: string, variables?: GraphqlVariables): Promise<TData>\n executeRaw?<TData>(query: string, variables?: GraphqlVariables): Promise<GraphqlRawResult<TData>>\n}\n\nexport interface GraphqlClient {\n query<TData, TVariables extends GraphqlVariables = GraphqlVariables>(\n query: GraphqlDocument,\n variables?: TVariables,\n ): Promise<TData>\n queryRaw<TData, TVariables extends GraphqlVariables = GraphqlVariables>(\n query: GraphqlDocument,\n variables?: TVariables,\n ): Promise<GraphqlRawResult<TData>>\n}\n\nexport type TokenClientOptions = {\n token: string\n graphqlUrl?: string\n}\n\nfunction queryToString(query: QueryLike): string {\n if (typeof query === \"string\") {\n return query\n }\n\n if (typeof query === \"object\" && query !== null && \"kind\" in query) {\n return print(query as DocumentNode)\n }\n\n return String(query)\n}\n\nfunction assertQuery(query: string): void {\n if (query.trim().length === 0) {\n throw new Error(\"GraphQL query must be non-empty\")\n }\n}\n\nexport function createGraphqlClient(transport: GraphqlTransport): GraphqlClient {\n return {\n async query<TData, TVariables extends GraphqlVariables = GraphqlVariables>(\n query: GraphqlDocument,\n variables?: TVariables,\n ): Promise<TData> {\n const queryText = queryToString(query)\n assertQuery(queryText)\n return transport.execute<TData>(queryText, variables)\n },\n async queryRaw<TData, TVariables extends GraphqlVariables = GraphqlVariables>(\n query: GraphqlDocument,\n variables?: TVariables,\n ): Promise<GraphqlRawResult<TData>> {\n const queryText = queryToString(query)\n assertQuery(queryText)\n // Both paths normalize transport-level errors into settled results\n try {\n if (transport.executeRaw) {\n return await transport.executeRaw<TData>(queryText, variables)\n }\n const data = await transport.execute<TData>(queryText, variables)\n return { data, errors: undefined }\n } catch (err) {\n return {\n data: undefined,\n errors: [{ message: err instanceof Error ? err.message : String(err) }],\n }\n }\n },\n }\n}\n\nexport function createGraphqlRequestClient(transport: GraphqlTransport): GraphQLClient {\n const client: Pick<GraphQLClient, \"request\"> = {\n request<TData, TVariables extends object = object>(\n documentOrOptions: RequestDocument | RequestOptions<TVariables, TData>,\n ...variablesAndRequestHeaders: unknown[]\n ): Promise<TData> {\n const options =\n typeof documentOrOptions === \"object\" &&\n documentOrOptions !== null &&\n \"document\" in documentOrOptions\n ? documentOrOptions\n : {\n document: documentOrOptions,\n variables: variablesAndRequestHeaders[0] as TVariables | undefined,\n }\n\n const queryText = queryToString(options.document)\n assertQuery(queryText)\n return transport.execute<TData>(queryText, options.variables as GraphqlVariables)\n },\n }\n\n return client as GraphQLClient\n}\n\nconst DEFAULT_GRAPHQL_URL = \"https://api.github.com/graphql\"\n\nexport function resolveGraphqlUrl(): string {\n if (process.env.GITHUB_GRAPHQL_URL) {\n return process.env.GITHUB_GRAPHQL_URL\n }\n\n if (process.env.GH_HOST) {\n return `https://${process.env.GH_HOST}/api/graphql`\n }\n\n return DEFAULT_GRAPHQL_URL\n}\n\ntype JsonPayload<TData> = {\n data?: TData\n errors?: GraphqlError[]\n message?: string\n}\n\nasync function fetchGraphql<TData>(\n url: string,\n token: string,\n query: string,\n variables?: GraphqlVariables,\n): Promise<JsonPayload<TData>> {\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({ query, variables: variables ?? {} }),\n })\n\n if (!response.ok) {\n let message = `GraphQL request failed (${response.status})`\n try {\n const body = (await response.json()) as JsonPayload<TData>\n if (body.message) {\n message = body.message\n }\n } catch {\n // Non-JSON error body — use status-based message\n }\n throw new Error(message)\n }\n\n try {\n return (await response.json()) as JsonPayload<TData>\n } catch {\n throw new Error(`GraphQL response is not valid JSON (${response.status})`)\n }\n}\n\nexport function createTokenTransport(token: string, graphqlUrl?: string): GraphqlTransport {\n const url = graphqlUrl ?? resolveGraphqlUrl()\n\n return {\n async execute<TData>(query: string, variables?: GraphqlVariables): Promise<TData> {\n const payload = await fetchGraphql<TData>(url, token, query, variables)\n\n if (payload.errors?.length) {\n throw new Error(payload.errors[0]?.message ?? \"GraphQL returned errors\")\n }\n\n if (payload.data === undefined) {\n throw new Error(\"GraphQL response missing data\")\n }\n\n return payload.data\n },\n\n async executeRaw<TData>(\n query: string,\n variables?: GraphqlVariables,\n ): Promise<GraphqlRawResult<TData>> {\n const payload = await fetchGraphql<TData>(url, token, query, variables)\n return {\n data: payload.data,\n errors: payload.errors?.length ? payload.errors : undefined,\n }\n },\n }\n}\n"],"mappings":"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","names":[]}