@atolis-hq/wake 0.1.16 → 0.1.18
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/README.md
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
# Wake
|
|
2
2
|
|
|
3
|
-
Wake is a
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
Wake is a control plane for autonomous software engineering. It watches the
|
|
4
|
+
channels your team already uses, coordinates agent activity and involves humans
|
|
5
|
+
when needed, and keeps the durable record attached to the work instead of the
|
|
6
|
+
terminal session that happened to run it.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
Create an issue, assign Wake, and keep doing your own work. Wake investigates,
|
|
9
|
+
asks for input when human judgment matters, proposes a plan, launches local
|
|
10
|
+
coding-agent CLIs to implement changes, opens pull requests, and carries the
|
|
11
|
+
conversation forward wherever the work is already happening.
|
|
12
|
+
|
|
13
|
+
Wake owns coordination. Coding agents execute the work.
|
|
10
14
|
|
|
11
15
|
## The Problem
|
|
12
16
|
|
|
@@ -27,10 +31,11 @@ out of the token-burning path wherever possible.
|
|
|
27
31
|
|
|
28
32
|
## Vision
|
|
29
33
|
|
|
30
|
-
Wake should make reliable, resumable, token-aware
|
|
34
|
+
Wake should make reliable, resumable, token-aware autonomous engineering
|
|
31
35
|
practical. The default operating model is asynchronous and channel-driven: work
|
|
32
|
-
enters
|
|
33
|
-
locally in an inspectable workspace or
|
|
36
|
+
enters through durable external systems, Wake keeps humans in the loop at useful
|
|
37
|
+
decision points, and execution happens locally in an inspectable workspace or
|
|
38
|
+
sandbox.
|
|
34
39
|
|
|
35
40
|
Wake is not trying to replace coding agents, issue trackers, or source control.
|
|
36
41
|
It coordinates across them. Over time it should become the layer that picks
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Octokit } from '@octokit/rest';
|
|
2
|
+
import { createEtagCache, fetchPaginatedWithEtag, fetchSingleWithEtag, } from './github-etag-cache.js';
|
|
2
3
|
export function createGitHubClient(token) {
|
|
3
4
|
const octokit = new Octokit({ auth: token });
|
|
5
|
+
const etagCache = createEtagCache();
|
|
4
6
|
return {
|
|
5
7
|
async getAuthenticatedLogin() {
|
|
6
8
|
const { data } = await octokit.rest.users.getAuthenticated();
|
|
@@ -12,27 +14,31 @@ export function createGitHubClient(token) {
|
|
|
12
14
|
// issues. Stop paginating as soon as the cap is reached.
|
|
13
15
|
async listIssues(owner, repo, maxResults, since) {
|
|
14
16
|
const perPage = Math.min(maxResults, 100);
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
owner
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return results.slice(0, maxResults);
|
|
17
|
+
return fetchPaginatedWithEtag({
|
|
18
|
+
cache: etagCache,
|
|
19
|
+
cacheKey: `issues:${owner}/${repo}`,
|
|
20
|
+
maxResults,
|
|
21
|
+
pages: (headers) => octokit.paginate.iterator(octokit.rest.issues.listForRepo, {
|
|
22
|
+
owner,
|
|
23
|
+
repo,
|
|
24
|
+
state: 'all',
|
|
25
|
+
per_page: perPage,
|
|
26
|
+
...(since === undefined ? {} : { since }),
|
|
27
|
+
...(headers === undefined ? {} : { headers }),
|
|
28
|
+
}),
|
|
29
|
+
});
|
|
29
30
|
},
|
|
30
31
|
async listComments(owner, repo, issueNumber, perPage) {
|
|
31
|
-
return
|
|
32
|
-
|
|
33
|
-
repo
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
return fetchPaginatedWithEtag({
|
|
33
|
+
cache: etagCache,
|
|
34
|
+
cacheKey: `issue-comments:${owner}/${repo}#${issueNumber}`,
|
|
35
|
+
pages: (headers) => octokit.paginate.iterator(octokit.rest.issues.listComments, {
|
|
36
|
+
owner,
|
|
37
|
+
repo,
|
|
38
|
+
issue_number: issueNumber,
|
|
39
|
+
per_page: perPage,
|
|
40
|
+
...(headers === undefined ? {} : { headers }),
|
|
41
|
+
}),
|
|
36
42
|
});
|
|
37
43
|
},
|
|
38
44
|
async createComment(owner, repo, issueNumber, body) {
|
|
@@ -60,10 +66,18 @@ export function createGitHubClient(token) {
|
|
|
60
66
|
return data;
|
|
61
67
|
},
|
|
62
68
|
async getRequiredStatusChecks(owner, repo, branch) {
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
repo
|
|
66
|
-
|
|
69
|
+
const data = await fetchSingleWithEtag({
|
|
70
|
+
cache: etagCache,
|
|
71
|
+
cacheKey: `required-status-checks:${owner}/${repo}@${branch}`,
|
|
72
|
+
request: async (headers) => {
|
|
73
|
+
const response = await octokit.rest.repos.getBranch({
|
|
74
|
+
owner,
|
|
75
|
+
repo,
|
|
76
|
+
branch,
|
|
77
|
+
...(headers === undefined ? {} : { headers }),
|
|
78
|
+
});
|
|
79
|
+
return { data: response.data, headers: response.headers ?? {} };
|
|
80
|
+
},
|
|
67
81
|
});
|
|
68
82
|
const requiredStatusChecks = data.protection?.required_status_checks;
|
|
69
83
|
return {
|
|
@@ -74,52 +88,77 @@ export function createGitHubClient(token) {
|
|
|
74
88
|
};
|
|
75
89
|
},
|
|
76
90
|
async listCheckRunsForRef(owner, repo, ref) {
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
repo
|
|
80
|
-
|
|
81
|
-
|
|
91
|
+
const data = await fetchSingleWithEtag({
|
|
92
|
+
cache: etagCache,
|
|
93
|
+
cacheKey: `check-runs:${owner}/${repo}@${ref}`,
|
|
94
|
+
request: async (headers) => {
|
|
95
|
+
const response = await octokit.rest.checks.listForRef({
|
|
96
|
+
owner,
|
|
97
|
+
repo,
|
|
98
|
+
ref,
|
|
99
|
+
per_page: 100,
|
|
100
|
+
...(headers === undefined ? {} : { headers }),
|
|
101
|
+
});
|
|
102
|
+
return { data: response.data, headers: response.headers ?? {} };
|
|
103
|
+
},
|
|
82
104
|
});
|
|
83
105
|
return data.check_runs;
|
|
84
106
|
},
|
|
85
107
|
async getCombinedStatusForRef(owner, repo, ref) {
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
repo
|
|
89
|
-
|
|
108
|
+
const data = await fetchSingleWithEtag({
|
|
109
|
+
cache: etagCache,
|
|
110
|
+
cacheKey: `combined-status:${owner}/${repo}@${ref}`,
|
|
111
|
+
request: async (headers) => {
|
|
112
|
+
const response = await octokit.rest.repos.getCombinedStatusForRef({
|
|
113
|
+
owner,
|
|
114
|
+
repo,
|
|
115
|
+
ref,
|
|
116
|
+
...(headers === undefined ? {} : { headers }),
|
|
117
|
+
});
|
|
118
|
+
return { data: response.data, headers: response.headers ?? {} };
|
|
119
|
+
},
|
|
90
120
|
});
|
|
91
121
|
return data.statuses;
|
|
92
122
|
},
|
|
93
123
|
async listPullRequests(owner, repo, maxResults) {
|
|
94
124
|
const perPage = Math.min(maxResults, 100);
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
owner
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
return results.slice(0, maxResults);
|
|
125
|
+
return fetchPaginatedWithEtag({
|
|
126
|
+
cache: etagCache,
|
|
127
|
+
cacheKey: `pulls:${owner}/${repo}`,
|
|
128
|
+
maxResults,
|
|
129
|
+
pages: (headers) => octokit.paginate.iterator(octokit.rest.pulls.list, {
|
|
130
|
+
owner,
|
|
131
|
+
repo,
|
|
132
|
+
state: 'open',
|
|
133
|
+
per_page: perPage,
|
|
134
|
+
...(headers === undefined ? {} : { headers }),
|
|
135
|
+
}),
|
|
136
|
+
});
|
|
108
137
|
},
|
|
109
138
|
async listReviews(owner, repo, pullNumber, perPage) {
|
|
110
|
-
return
|
|
111
|
-
|
|
112
|
-
repo
|
|
113
|
-
|
|
114
|
-
|
|
139
|
+
return fetchPaginatedWithEtag({
|
|
140
|
+
cache: etagCache,
|
|
141
|
+
cacheKey: `pr-reviews:${owner}/${repo}#${pullNumber}`,
|
|
142
|
+
pages: (headers) => octokit.paginate.iterator(octokit.rest.pulls.listReviews, {
|
|
143
|
+
owner,
|
|
144
|
+
repo,
|
|
145
|
+
pull_number: pullNumber,
|
|
146
|
+
per_page: perPage,
|
|
147
|
+
...(headers === undefined ? {} : { headers }),
|
|
148
|
+
}),
|
|
115
149
|
});
|
|
116
150
|
},
|
|
117
151
|
async listReviewComments(owner, repo, pullNumber, perPage) {
|
|
118
|
-
return
|
|
119
|
-
|
|
120
|
-
repo
|
|
121
|
-
|
|
122
|
-
|
|
152
|
+
return fetchPaginatedWithEtag({
|
|
153
|
+
cache: etagCache,
|
|
154
|
+
cacheKey: `pr-review-comments:${owner}/${repo}#${pullNumber}`,
|
|
155
|
+
pages: (headers) => octokit.paginate.iterator(octokit.rest.pulls.listReviewComments, {
|
|
156
|
+
owner,
|
|
157
|
+
repo,
|
|
158
|
+
pull_number: pullNumber,
|
|
159
|
+
per_page: perPage,
|
|
160
|
+
...(headers === undefined ? {} : { headers }),
|
|
161
|
+
}),
|
|
123
162
|
});
|
|
124
163
|
},
|
|
125
164
|
async replyToReviewComment(owner, repo, pullNumber, commentId, body) {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export function createEtagCache() {
|
|
2
|
+
return new Map();
|
|
3
|
+
}
|
|
4
|
+
function isNotModifiedError(error) {
|
|
5
|
+
return (typeof error === 'object' &&
|
|
6
|
+
error !== null &&
|
|
7
|
+
'status' in error &&
|
|
8
|
+
error.status === 304);
|
|
9
|
+
}
|
|
10
|
+
export async function fetchSingleWithEtag(input) {
|
|
11
|
+
const cached = input.cache.get(input.cacheKey);
|
|
12
|
+
try {
|
|
13
|
+
const response = await input.request(cached === undefined ? undefined : { 'if-none-match': cached.etag });
|
|
14
|
+
if (typeof response.headers.etag === 'string') {
|
|
15
|
+
input.cache.set(input.cacheKey, { etag: response.headers.etag, data: response.data });
|
|
16
|
+
}
|
|
17
|
+
return response.data;
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
if (isNotModifiedError(error) && cached !== undefined) {
|
|
21
|
+
return cached.data;
|
|
22
|
+
}
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export async function fetchPaginatedWithEtag(input) {
|
|
27
|
+
const cached = input.cache.get(input.cacheKey);
|
|
28
|
+
const results = [];
|
|
29
|
+
let pageCount = 0;
|
|
30
|
+
let lastHeaders = {};
|
|
31
|
+
try {
|
|
32
|
+
for await (const page of input.pages(cached === undefined ? undefined : { 'if-none-match': cached.etag })) {
|
|
33
|
+
pageCount += 1;
|
|
34
|
+
lastHeaders = page.headers;
|
|
35
|
+
results.push(...page.data);
|
|
36
|
+
if (input.maxResults !== undefined && results.length >= input.maxResults) {
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
if (isNotModifiedError(error) && cached !== undefined) {
|
|
43
|
+
return input.maxResults === undefined ? cached.data : cached.data.slice(0, input.maxResults);
|
|
44
|
+
}
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
const truncated = input.maxResults !== undefined && results.length > input.maxResults
|
|
48
|
+
? results.slice(0, input.maxResults)
|
|
49
|
+
: results;
|
|
50
|
+
if (pageCount <= 1 && typeof lastHeaders.etag === 'string') {
|
|
51
|
+
input.cache.set(input.cacheKey, { etag: lastHeaders.etag, data: truncated });
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
input.cache.delete(input.cacheKey);
|
|
55
|
+
}
|
|
56
|
+
return truncated;
|
|
57
|
+
}
|
package/dist/src/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const wakeVersion = "0.1.
|
|
1
|
+
export const wakeVersion = "0.1.18+g6b6248c";
|