@atolis-hq/wake 0.3.81 → 0.3.82

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.
@@ -229,6 +229,21 @@ function createSystemApplications(root, now) {
229
229
  meta: sampledMeta(sampledAt),
230
230
  };
231
231
  },
232
+ async commands() {
233
+ const sampledAt = now();
234
+ return {
235
+ data: {
236
+ adapters: root.providers
237
+ .filter((instance) => instance.commands !== undefined)
238
+ .map((instance) => ({
239
+ adapter: instance.adapter,
240
+ provider: instance.provider,
241
+ commands: instance.commands(),
242
+ })),
243
+ },
244
+ meta: sampledMeta(sampledAt),
245
+ };
246
+ },
232
247
  };
233
248
  }
234
249
  function commandAccepted(command, acceptedAt) {
@@ -108,4 +108,4 @@ export function resolveWakeVersion(options = {}) {
108
108
  return `g${headHash.slice(0, 7)}`;
109
109
  return '0.1.0-dev';
110
110
  }
111
- export const wakeVersion = "gb8f09ad";
111
+ export const wakeVersion = "ga32fb11";
@@ -1,15 +1,17 @@
1
1
  import { ReviewActorKind } from '../../../activities/index.js';
2
+ import { GitHubBuiltInCommand } from '../contracts/vocabulary.js';
2
3
  export function isHumanNonWakeReply(actorKind, body) {
3
4
  return actorKind === ReviewActorKind.Human && !body.includes('<!-- wake:');
4
5
  }
5
6
  export function recognizedCommand(body) {
6
7
  const normalized = body.trim().toLowerCase();
7
- if (normalized === '/approved')
8
- return '/approved';
9
- if (normalized === '/changes' || normalized.startsWith('/changes '))
10
- return '/changes';
11
- if (normalized === '/retry')
12
- return '/retry';
8
+ if (normalized === GitHubBuiltInCommand.Approved)
9
+ return GitHubBuiltInCommand.Approved;
10
+ if (normalized === GitHubBuiltInCommand.Changes ||
11
+ normalized.startsWith(`${GitHubBuiltInCommand.Changes} `))
12
+ return GitHubBuiltInCommand.Changes;
13
+ if (normalized === GitHubBuiltInCommand.Retry)
14
+ return GitHubBuiltInCommand.Retry;
13
15
  return null;
14
16
  }
15
17
  export function isPlainReply(body) {
@@ -17,5 +19,5 @@ export function isPlainReply(body) {
17
19
  return normalized.length > 0 && !normalized.startsWith('/');
18
20
  }
19
21
  export function shouldResumeBlockedStage(command, plainReply) {
20
- return command === '/changes' || plainReply;
22
+ return command === GitHubBuiltInCommand.Changes || plainReply;
21
23
  }
@@ -3,7 +3,7 @@ import { ActivityOutcomeKind, ReviewActorKind, ReviewDecisionKind, ReviewerAutho
3
3
  import { ApprovalAuthorityKind, selectOperatorRetryTarget, } from '../../../orchestration/index.js';
4
4
  import { BuiltInResourceKind, ResourceCorrelationRole, ResourceStreamKind, resourceId, } from '../../../resources/index.js';
5
5
  import { WorkStatus } from '../../../work/index.js';
6
- import { UnknownGitHubIdentity } from '../contracts/vocabulary.js';
6
+ import { GitHubBuiltInCommand, UnknownGitHubIdentity } from '../contracts/vocabulary.js';
7
7
  import { isHumanNonWakeReply, isPlainReply, recognizedCommand, shouldResumeBlockedStage, } from './inbound-comment-syntax.js';
8
8
  import { commandContext } from './inbound-context.js';
9
9
  import { ignoreIneligibleOperatorRetry } from './operator-retry-command.js';
@@ -77,7 +77,7 @@ async function applyIssueReviewSignal(input) {
77
77
  const resource = await resources.get(resourceIdValue);
78
78
  const command = recognizedCommand(event.payload.body);
79
79
  const plainReply = isPlainReply(event.payload.body);
80
- if (command === '/retry') {
80
+ if (command === GitHubBuiltInCommand.Retry) {
81
81
  return applyIssueRetrySignal({
82
82
  event,
83
83
  resources,
@@ -93,7 +93,9 @@ async function applyIssueReviewSignal(input) {
93
93
  work,
94
94
  orchestration,
95
95
  resourceId: resourceIdValue,
96
- outcome: command === '/approved' ? ActivityOutcomeKind.Done : ActivityOutcomeKind.Rejected,
96
+ outcome: command === GitHubBuiltInCommand.Approved
97
+ ? ActivityOutcomeKind.Done
98
+ : ActivityOutcomeKind.Rejected,
97
99
  acceptWaitingSignal: command !== null,
98
100
  resumeBlockedOnChanges: shouldResumeBlockedStage(command, plainReply),
99
101
  });
@@ -153,8 +155,10 @@ async function applyIssueApprovalSignal(input) {
153
155
  work,
154
156
  orchestration,
155
157
  resourceId: resourceIdValue,
156
- outcome: command === '/approved' ? ActivityOutcomeKind.Done : ActivityOutcomeKind.Rejected,
157
- resumeBlockedOnChanges: command === '/changes',
158
+ outcome: command === GitHubBuiltInCommand.Approved
159
+ ? ActivityOutcomeKind.Done
160
+ : ActivityOutcomeKind.Rejected,
161
+ resumeBlockedOnChanges: command === GitHubBuiltInCommand.Changes,
158
162
  });
159
163
  }
160
164
  async function applyPullRequestWorkflowSignal(input) {
@@ -1,7 +1,8 @@
1
1
  import { ReviewDecisionKind, } from '../../../activities/index.js';
2
+ import { GitHubBuiltInCommand } from '../contracts/vocabulary.js';
2
3
  export function translateGitHubReviewCommand(input) {
3
4
  const command = input.body.trim();
4
- if (command !== '/accepted' && command !== '/changes')
5
+ if (command !== GitHubBuiltInCommand.Accepted && command !== GitHubBuiltInCommand.Changes)
5
6
  return null;
6
7
  return {
7
8
  resourceId: input.resourceId,
@@ -11,6 +12,8 @@ export function translateGitHubReviewCommand(input) {
11
12
  resourceAuthorId: input.resourceAuthorId,
12
13
  authorization: input.authorization,
13
14
  providerEventId: input.providerEventId,
14
- kind: command === '/accepted' ? ReviewDecisionKind.Accepted : ReviewDecisionKind.ChangesRequested,
15
+ kind: command === GitHubBuiltInCommand.Accepted
16
+ ? ReviewDecisionKind.Accepted
17
+ : ReviewDecisionKind.ChangesRequested,
15
18
  };
16
19
  }
@@ -52,5 +52,10 @@ export const gitHubConfigSchema = z
52
52
  .object({ postStatusComments: z.boolean().default(true) })
53
53
  .strict()
54
54
  .default({ postStatusComments: true }),
55
+ // Additional command syntax to advertise on the commands/instructions
56
+ // surface alongside the adapter's built-in commands. Purely descriptive:
57
+ // Wake does not recognize these itself, so any behavior they imply must
58
+ // be handled by whatever reads the comment (e.g. a workflow prompt).
59
+ commands: z.array(z.string().trim().min(1)).default([]),
55
60
  })
56
61
  .strict();
@@ -54,3 +54,15 @@ export const GitHubOutboundAction = {
54
54
  Reply: 'reply',
55
55
  Close: 'close',
56
56
  };
57
+ // Comment-channel commands the GitHub adapter recognizes from human replies.
58
+ // /approved and /changes drive issue-review and PR-issue-comment signals;
59
+ // /accepted and /changes drive formal (native) PR review comments; /retry
60
+ // resumes a blocked/failed stage. Kept as the single source of truth for both
61
+ // recognition (inbound-comment-syntax.ts, review-command-translator.ts) and
62
+ // the commands/instructions surface, so the two cannot drift.
63
+ export const GitHubBuiltInCommand = defineClosedVocabulary({
64
+ Approved: '/approved',
65
+ Accepted: '/accepted',
66
+ Changes: '/changes',
67
+ Retry: '/retry',
68
+ });
@@ -1,4 +1,5 @@
1
1
  import { ReviewerAuthorizationSource, } from '../../../activities/index.js';
2
+ import { GitHubBuiltInCommand } from '../contracts/vocabulary.js';
2
3
  import { issueCommentObservation } from './issue-source.js';
3
4
  import { mergeBatches, reportPartialPollFailure } from './poll-watermark.js';
4
5
  import { githubReviewObservation } from './review-source.js';
@@ -69,7 +70,7 @@ async function issueCommentEventsForComment(context, issue, comment) {
69
70
  return event === null ? [] : [event];
70
71
  }
71
72
  async function retryAuthorization(context, comment) {
72
- if (comment.body?.trim().toLowerCase() !== '/retry')
73
+ if (comment.body?.trim().toLowerCase() !== GitHubBuiltInCommand.Retry)
73
74
  return undefined;
74
75
  const login = comment.user?.login;
75
76
  if (login === undefined || context.client.collaboratorPermission === undefined)
@@ -3,7 +3,7 @@ import { createEventDraft, EventActorKind, EventSourceKind } from '../../../kern
3
3
  import { integrationStream } from '../../contracts/streams.js';
4
4
  import { GitHubEventType } from '../contracts/events.js';
5
5
  import { formatGitHubResourceKey } from '../contracts/external-key.js';
6
- import { GitHubAdapter, GitHubReviewState, UnknownGitHubIdentity, } from '../contracts/vocabulary.js';
6
+ import { GitHubAdapter, GitHubBuiltInCommand, GitHubReviewState, UnknownGitHubIdentity, } from '../contracts/vocabulary.js';
7
7
  export function githubReviewObservation(input) {
8
8
  const body = input.review.body?.trim();
9
9
  const command = reviewCommand(input.review.state);
@@ -62,8 +62,8 @@ function configuredAuthorization(actorId, reviewers) {
62
62
  }
63
63
  function reviewCommand(state) {
64
64
  if (state === GitHubReviewState.Approved)
65
- return '/accepted';
66
- return state === GitHubReviewState.ChangesRequested ? '/changes' : null;
65
+ return GitHubBuiltInCommand.Accepted;
66
+ return state === GitHubReviewState.ChangesRequested ? GitHubBuiltInCommand.Changes : null;
67
67
  }
68
68
  function sameIdentity(left, right) {
69
69
  return left.toLowerCase() === right.toLowerCase();
@@ -6,6 +6,7 @@ import { translateGitHubOutbound } from './application/outbound-translator.js';
6
6
  import { createGitHubWakeLabelReconciler } from './application/wake-labels.js';
7
7
  import { gitHubConfigSchema } from './contracts/config.js';
8
8
  import { GitHubEventType } from './contracts/events.js';
9
+ import { GitHubBuiltInCommand } from './contracts/vocabulary.js';
9
10
  import { createGitHubAdapterHealthRegistry } from './infrastructure/adapter-health-registry.js';
10
11
  import { createGitHubClient } from './infrastructure/client.js';
11
12
  import { createGitHubDelivery } from './infrastructure/delivery.js';
@@ -43,6 +44,10 @@ export const gitHubProviderDefinition = {
43
44
  requests,
44
45
  }),
45
46
  health: () => health.snapshotAll(),
47
+ commands: () => [
48
+ ...Object.values(GitHubBuiltInCommand).map((syntax) => ({ syntax })),
49
+ ...config.commands.map((syntax) => ({ syntax })),
50
+ ],
46
51
  delivery: createGitHubDelivery(async (intent, idempotencyKey) => {
47
52
  const resource = await services.resources.get(resourceId(intent.resourceId));
48
53
  if (resource === null)
@@ -36,6 +36,8 @@ async function readSingleton(applications, url) {
36
36
  return noQuery(url, async () => ok(await applications.system.health()));
37
37
  case '/api/v1/system/configuration':
38
38
  return noQuery(url, async () => ok(await applications.system.configuration()));
39
+ case '/api/v1/system/commands':
40
+ return noQuery(url, async () => ok(await applications.system.commands()));
39
41
  default:
40
42
  return undefined;
41
43
  }
@@ -1 +1,5 @@
1
- export const systemRoutes = ['/api/v1/system/health', '/api/v1/system/configuration'];
1
+ export const systemRoutes = [
2
+ '/api/v1/system/health',
3
+ '/api/v1/system/configuration',
4
+ '/api/v1/system/commands',
5
+ ];