experimental-ash 0.56.0 → 0.57.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.
- package/CHANGELOG.md +9 -0
- package/dist/docs/internals/compiler-and-artifacts.md +1 -1
- package/dist/docs/internals/context.md +3 -3
- package/dist/docs/public/advanced/typescript-api.md +19 -0
- package/dist/docs/public/advanced/vercel-deployment.md +2 -1
- package/dist/docs/public/channels/github.md +145 -0
- package/dist/docs/public/channels/index.md +23 -2
- package/dist/docs/public/sandbox.md +18 -3
- package/dist/docs/public/subagents.mdx +7 -2
- package/dist/src/compiler/manifest.d.ts +8 -2
- package/dist/src/compiler/manifest.js +1 -1
- package/dist/src/compiler/normalize-sandbox.js +1 -1
- package/dist/src/execution/remote-agent-dispatch.js +1 -1
- package/dist/src/execution/subagent-tool.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/authored-definition/sandbox.d.ts +2 -1
- package/dist/src/internal/authored-definition/sandbox.js +1 -1
- package/dist/src/packages/ash-scaffold/src/channels.js +1 -1
- package/dist/src/public/channels/github/api.d.ts +166 -0
- package/dist/src/public/channels/github/api.js +1 -0
- package/dist/src/public/channels/github/auth.d.ts +83 -0
- package/dist/src/public/channels/github/auth.js +2 -0
- package/dist/src/public/channels/github/binding.d.ts +49 -0
- package/dist/src/public/channels/github/binding.js +1 -0
- package/dist/src/public/channels/github/checkout.d.ts +48 -0
- package/dist/src/public/channels/github/checkout.js +1 -0
- package/dist/src/public/channels/github/constants.d.ts +2 -0
- package/dist/src/public/channels/github/constants.js +1 -0
- package/dist/src/public/channels/github/defaults.d.ts +21 -0
- package/dist/src/public/channels/github/defaults.js +3 -0
- package/dist/src/public/channels/github/dispatch.d.ts +34 -0
- package/dist/src/public/channels/github/dispatch.js +1 -0
- package/dist/src/public/channels/github/githubChannel.d.ts +109 -0
- package/dist/src/public/channels/github/githubChannel.js +1 -0
- package/dist/src/public/channels/github/inbound.d.ts +183 -0
- package/dist/src/public/channels/github/inbound.js +2 -0
- package/dist/src/public/channels/github/index.d.ts +9 -0
- package/dist/src/public/channels/github/index.js +1 -0
- package/dist/src/public/channels/github/limits.d.ts +4 -0
- package/dist/src/public/channels/github/limits.js +2 -0
- package/dist/src/public/channels/github/pr-context.d.ts +45 -0
- package/dist/src/public/channels/github/pr-context.js +5 -0
- package/dist/src/public/channels/github/state.d.ts +48 -0
- package/dist/src/public/channels/github/state.js +1 -0
- package/dist/src/public/channels/github/verify.d.ts +35 -0
- package/dist/src/public/channels/github/verify.js +1 -0
- package/dist/src/public/definitions/sandbox.d.ts +3 -3
- package/dist/src/public/sandbox/index.d.ts +1 -1
- package/dist/src/runtime/resolve-sandbox.js +1 -1
- package/dist/src/runtime/sandbox/keys.js +1 -1
- package/dist/src/runtime/sandbox/template-plan.d.ts +5 -0
- package/dist/src/runtime/sandbox/template-plan.js +1 -1
- package/dist/src/runtime/subagents/registry.js +1 -1
- package/dist/src/runtime/types.d.ts +6 -2
- package/dist/src/shared/sandbox-definition.d.ts +22 -2
- package/package.json +6 -1
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import type { UserContent } from "ai";
|
|
2
|
+
import { type JsonObject } from "#shared/json.js";
|
|
3
|
+
/** GitHub conversation kinds represented by the channel state. */
|
|
4
|
+
export type GitHubConversationKind = "issue" | "pull_request" | "review_thread";
|
|
5
|
+
/** Stable repository identity normalized from webhook payloads. */
|
|
6
|
+
export interface GitHubRepositoryRef {
|
|
7
|
+
readonly fullName: string;
|
|
8
|
+
readonly id: number;
|
|
9
|
+
readonly name: string;
|
|
10
|
+
readonly owner: string;
|
|
11
|
+
readonly private: boolean;
|
|
12
|
+
}
|
|
13
|
+
/** GitHub actor metadata normalized from webhook payloads. */
|
|
14
|
+
export interface GitHubUser {
|
|
15
|
+
readonly htmlUrl: string | undefined;
|
|
16
|
+
readonly id: number;
|
|
17
|
+
readonly login: string;
|
|
18
|
+
readonly type: string;
|
|
19
|
+
readonly url: string | undefined;
|
|
20
|
+
}
|
|
21
|
+
/** Verified GitHub webhook delivery headers. */
|
|
22
|
+
export interface GitHubDelivery {
|
|
23
|
+
readonly event: string;
|
|
24
|
+
readonly hookId: string | undefined;
|
|
25
|
+
readonly id: string;
|
|
26
|
+
}
|
|
27
|
+
/** Channel-local conversation reference. */
|
|
28
|
+
export interface GitHubConversationRef {
|
|
29
|
+
readonly issueNumber: number | null;
|
|
30
|
+
readonly kind: GitHubConversationKind;
|
|
31
|
+
readonly pullRequestNumber: number | null;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Normalized GitHub comment handed to the `onComment` hook. Covers issue and PR
|
|
35
|
+
* timeline comments and inline review comments alike; `ctx.conversation.kind`
|
|
36
|
+
* distinguishes them.
|
|
37
|
+
*/
|
|
38
|
+
export interface GitHubComment {
|
|
39
|
+
readonly author: GitHubUser | undefined;
|
|
40
|
+
readonly body: string;
|
|
41
|
+
readonly htmlUrl: string | undefined;
|
|
42
|
+
readonly id: number;
|
|
43
|
+
readonly raw: JsonObject;
|
|
44
|
+
readonly url: string | undefined;
|
|
45
|
+
}
|
|
46
|
+
/** Normalized issue/PR timeline comment. */
|
|
47
|
+
export interface GitHubIssueComment {
|
|
48
|
+
readonly author: GitHubUser | undefined;
|
|
49
|
+
readonly body: string;
|
|
50
|
+
readonly htmlUrl: string | undefined;
|
|
51
|
+
readonly id: number;
|
|
52
|
+
readonly issueNumber: number;
|
|
53
|
+
readonly pullRequestNumber: number | null;
|
|
54
|
+
readonly raw: JsonObject;
|
|
55
|
+
readonly url: string | undefined;
|
|
56
|
+
}
|
|
57
|
+
/** Normalized inline pull-request review comment. */
|
|
58
|
+
export interface GitHubPullRequestReviewComment {
|
|
59
|
+
readonly author: GitHubUser | undefined;
|
|
60
|
+
readonly body: string;
|
|
61
|
+
readonly htmlUrl: string | undefined;
|
|
62
|
+
readonly id: number;
|
|
63
|
+
readonly inReplyToId: number | null;
|
|
64
|
+
readonly pullRequestNumber: number;
|
|
65
|
+
readonly raw: JsonObject;
|
|
66
|
+
readonly reviewThreadRootCommentId: number;
|
|
67
|
+
readonly url: string | undefined;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Common `issues` webhook actions, kept open to any action GitHub sends so
|
|
71
|
+
* authors get autocomplete without losing forward compatibility.
|
|
72
|
+
*/
|
|
73
|
+
export type GitHubIssueAction = "assigned" | "closed" | "edited" | "labeled" | "opened" | "reopened" | "unassigned" | "unlabeled" | (string & {});
|
|
74
|
+
/** Common `pull_request` webhook actions, kept open to any action GitHub sends. */
|
|
75
|
+
export type GitHubPullRequestAction = "closed" | "edited" | "labeled" | "opened" | "ready_for_review" | "reopened" | "synchronize" | "unlabeled" | (string & {});
|
|
76
|
+
/** Normalized issue event payload. */
|
|
77
|
+
export interface GitHubIssueEvent {
|
|
78
|
+
readonly action: GitHubIssueAction;
|
|
79
|
+
readonly issueNumber: number;
|
|
80
|
+
readonly raw: JsonObject;
|
|
81
|
+
}
|
|
82
|
+
/** Normalized pull-request event payload. */
|
|
83
|
+
export interface GitHubPullRequestEvent {
|
|
84
|
+
readonly action: GitHubPullRequestAction;
|
|
85
|
+
readonly headSha: string | null;
|
|
86
|
+
readonly pullRequestNumber: number;
|
|
87
|
+
readonly raw: JsonObject;
|
|
88
|
+
}
|
|
89
|
+
export interface GitHubPingEvent extends GitHubInboundEventBase {
|
|
90
|
+
readonly kind: "ping";
|
|
91
|
+
}
|
|
92
|
+
export interface GitHubIssueCommentEvent extends GitHubInboundEventBase {
|
|
93
|
+
readonly action: string;
|
|
94
|
+
readonly baseRef: string | null;
|
|
95
|
+
readonly baseSha: string | null;
|
|
96
|
+
readonly comment: GitHubIssueComment;
|
|
97
|
+
readonly conversation: GitHubConversationRef;
|
|
98
|
+
readonly defaultBranch: string | null;
|
|
99
|
+
readonly headRef: string | null;
|
|
100
|
+
readonly headSha: string | null;
|
|
101
|
+
readonly kind: "issue_comment";
|
|
102
|
+
}
|
|
103
|
+
export interface GitHubPullRequestReviewCommentEvent extends GitHubInboundEventBase {
|
|
104
|
+
readonly action: string;
|
|
105
|
+
readonly baseRef: string | null;
|
|
106
|
+
readonly baseSha: string | null;
|
|
107
|
+
readonly comment: GitHubPullRequestReviewComment;
|
|
108
|
+
readonly conversation: GitHubConversationRef;
|
|
109
|
+
readonly defaultBranch: string | null;
|
|
110
|
+
readonly headRef: string | null;
|
|
111
|
+
readonly headSha: string | null;
|
|
112
|
+
readonly kind: "pull_request_review_comment";
|
|
113
|
+
}
|
|
114
|
+
export interface GitHubIssueWebhookEvent extends GitHubInboundEventBase {
|
|
115
|
+
readonly action: string;
|
|
116
|
+
readonly conversation: GitHubConversationRef;
|
|
117
|
+
readonly issue: GitHubIssueEvent;
|
|
118
|
+
readonly kind: "issues";
|
|
119
|
+
}
|
|
120
|
+
export interface GitHubPullRequestWebhookEvent extends GitHubInboundEventBase {
|
|
121
|
+
readonly action: string;
|
|
122
|
+
readonly baseRef: string | null;
|
|
123
|
+
readonly baseSha: string | null;
|
|
124
|
+
readonly conversation: GitHubConversationRef;
|
|
125
|
+
readonly defaultBranch: string | null;
|
|
126
|
+
readonly headRef: string | null;
|
|
127
|
+
readonly headSha: string | null;
|
|
128
|
+
readonly kind: "pull_request";
|
|
129
|
+
readonly pullRequest: GitHubPullRequestEvent;
|
|
130
|
+
}
|
|
131
|
+
interface GitHubInboundEventBase {
|
|
132
|
+
readonly delivery: GitHubDelivery;
|
|
133
|
+
readonly installationId: number | undefined;
|
|
134
|
+
readonly raw: JsonObject;
|
|
135
|
+
readonly repository: GitHubRepositoryRef;
|
|
136
|
+
readonly sender: GitHubUser;
|
|
137
|
+
}
|
|
138
|
+
/** Parsed GitHub webhook event shape consumed by the channel. */
|
|
139
|
+
export type GitHubInboundEvent = GitHubIssueCommentEvent | GitHubIssueWebhookEvent | GitHubPingEvent | GitHubPullRequestReviewCommentEvent | GitHubPullRequestWebhookEvent;
|
|
140
|
+
/** Parsed mention trigger for a bot-directed GitHub comment. */
|
|
141
|
+
export interface GitHubCommentTrigger {
|
|
142
|
+
readonly kind: "mention";
|
|
143
|
+
readonly message: string;
|
|
144
|
+
readonly token: string;
|
|
145
|
+
}
|
|
146
|
+
/** Builds the channel-local continuation token for a GitHub conversation. */
|
|
147
|
+
export declare function githubContinuationToken(input: {
|
|
148
|
+
readonly conversationKind: GitHubConversationKind;
|
|
149
|
+
readonly issueNumber?: number | null;
|
|
150
|
+
readonly pullRequestNumber?: number | null;
|
|
151
|
+
readonly repositoryId: number;
|
|
152
|
+
readonly reviewThreadRootCommentId?: number | null;
|
|
153
|
+
}): string;
|
|
154
|
+
/** Returns true when a comment @mentions the bot and should wake the channel. */
|
|
155
|
+
export declare function shouldDispatchGitHubComment(input: {
|
|
156
|
+
readonly author?: GitHubUser;
|
|
157
|
+
readonly body: string;
|
|
158
|
+
readonly botName?: string;
|
|
159
|
+
}): boolean;
|
|
160
|
+
/** Extracts and strips the bot `@mention` from a comment body. */
|
|
161
|
+
export declare function extractGitHubCommentTrigger(input: {
|
|
162
|
+
readonly body: string;
|
|
163
|
+
readonly botName?: string;
|
|
164
|
+
}): GitHubCommentTrigger | null;
|
|
165
|
+
/** Parses GitHub webhook headers and body into an Ash-owned event shape. */
|
|
166
|
+
export declare function parseGitHubWebhookEvent(input: {
|
|
167
|
+
readonly body: string;
|
|
168
|
+
readonly contentType?: string;
|
|
169
|
+
readonly headers: Headers;
|
|
170
|
+
}): GitHubInboundEvent | null;
|
|
171
|
+
/** Renders deterministic GitHub metadata for the model-visible turn. */
|
|
172
|
+
export declare function formatGitHubContextBlock(input: {
|
|
173
|
+
readonly commentUrl?: string;
|
|
174
|
+
readonly deliveryId: string;
|
|
175
|
+
readonly headSha?: string | null;
|
|
176
|
+
readonly issueNumber?: number | null;
|
|
177
|
+
readonly pullRequestNumber?: number | null;
|
|
178
|
+
readonly repository: GitHubRepositoryRef;
|
|
179
|
+
readonly sender: GitHubUser;
|
|
180
|
+
}): string;
|
|
181
|
+
/** Prepends a `<github_context>` block to the inbound turn message. */
|
|
182
|
+
export declare function prependGitHubContext(message: string | UserContent, block: string): string | UserContent;
|
|
183
|
+
export {};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";function githubContinuationToken(e){return e.conversationKind===`issue`?`repo:${e.repositoryId}:issue:${requiredNumber(e.issueNumber,`issueNumber`)}`:e.conversationKind===`pull_request`?`repo:${e.repositoryId}:pull:${requiredNumber(e.pullRequestNumber,`pullRequestNumber`)}`:`repo:${e.repositoryId}:pull:${requiredNumber(e.pullRequestNumber,`pullRequestNumber`)}:review-comment:${requiredNumber(e.reviewThreadRootCommentId,`reviewThreadRootCommentId`)}`}function shouldDispatchGitHubComment(e){return isIgnoredGitHubComment(e.body,e.author,e.botName)?!1:extractGitHubCommentTrigger(e)!==null}function extractGitHubCommentTrigger(e){let t=e.botName?.trim();if(!t)return null;let n=RegExp(`@${escapeRegExp(t)}(?=$|[^A-Za-z0-9_-])`,`iu`).exec(e.body);if(n===null)return null;let r=n.index,i=r+n[0].length;return{kind:`mention`,message:`${e.body.slice(0,r)}${e.body.slice(i)}`.trim(),token:n[0]}}function parseGitHubWebhookEvent(e){let t=e.headers.get(`x-github-event`)??``,n=e.headers.get(`x-github-delivery`)??``;if(!t||!n)return null;let r=decodePayload(e.body,e.contentType),i=normalizeRepository(r.repository),a=normalizeUser(r.sender);if(i===null||a===void 0)return null;let o={delivery:{event:t,hookId:e.headers.get(`x-github-hook-id`)??void 0,id:n},installationId:readInstallationId(r.installation),raw:r,repository:i,sender:a};return t===`ping`?{...o,kind:`ping`}:t===`issue_comment`?parseIssueCommentEvent(o):t===`pull_request_review_comment`?parsePullRequestReviewCommentEvent(o):t===`issues`?parseIssueEvent(o):t===`pull_request`?parsePullRequestEvent(o):null}function formatGitHubContextBlock(e){return[`<github_context>`,`repository: ${e.repository.fullName}`,`repository_id: ${e.repository.id}`,...e.issueNumber!==void 0&&e.issueNumber!==null?[`issue_number: ${e.issueNumber}`]:[],...e.pullRequestNumber!==void 0&&e.pullRequestNumber!==null?[`pull_request_number: ${e.pullRequestNumber}`]:[],`sender: ${e.sender.login}`,`sender_type: ${e.sender.type}`,...e.commentUrl?[`comment_url: ${e.commentUrl}`]:[],...e.headSha?[`head_sha: ${e.headSha}`]:[],`delivery_id: ${e.deliveryId}`,`</github_context>`].join(`
|
|
2
|
+
`)}function prependGitHubContext(e,t){return typeof e==`string`?e.length>0?`${t}\n\n${e}`:t:[{text:t,type:`text`},...e]}function parseIssueCommentEvent(n){let r=isObject(n.raw.issue)?n.raw.issue:null,i=isObject(n.raw.comment)?parseJsonObject(n.raw.comment):null,a=typeof r?.number==`number`?r.number:void 0;if(i===null||r===null||a===void 0)return null;let o=isObject(r.pull_request)?a:null,s=readAction(n.raw),c={author:normalizeUser(i.user),body:typeof i.body==`string`?i.body:``,htmlUrl:typeof i.html_url==`string`?i.html_url:void 0,id:typeof i.id==`number`?i.id:0,issueNumber:a,pullRequestNumber:o,raw:i,url:typeof i.url==`string`?i.url:void 0};return{...n,action:s,baseRef:null,baseSha:null,comment:c,conversation:{issueNumber:a,kind:o===null?`issue`:`pull_request`,pullRequestNumber:o},defaultBranch:null,headRef:null,headSha:null,kind:`issue_comment`}}function parsePullRequestReviewCommentEvent(n){let r=isObject(n.raw.comment)?parseJsonObject(n.raw.comment):null,i=isObject(n.raw.pull_request)?n.raw.pull_request:null,a=typeof i?.number==`number`?i.number:void 0;if(r===null||a===void 0)return null;let o=typeof r.id==`number`?r.id:0,s=typeof r.in_reply_to_id==`number`?r.in_reply_to_id:null,c={author:normalizeUser(r.user),body:typeof r.body==`string`?r.body:``,htmlUrl:typeof r.html_url==`string`?r.html_url:void 0,id:o,inReplyToId:s,pullRequestNumber:a,raw:r,reviewThreadRootCommentId:s??o,url:typeof r.url==`string`?r.url:void 0};return{...n,action:readAction(n.raw),baseRef:readPullRequestBaseRef(i),baseSha:readPullRequestBaseSha(i),comment:c,conversation:{issueNumber:null,kind:`review_thread`,pullRequestNumber:a},defaultBranch:readPullRequestDefaultBranch(i),headRef:readPullRequestHeadRef(i),headSha:readPullRequestHeadSha(i),kind:`pull_request_review_comment`}}function parseIssueEvent(n){let r=isObject(n.raw.issue)?n.raw.issue:null,i=typeof r?.number==`number`?r.number:void 0;return i===void 0?null:{...n,action:readAction(n.raw),conversation:{issueNumber:i,kind:`issue`,pullRequestNumber:null},issue:{action:readAction(n.raw),issueNumber:i,raw:parseJsonObject(r)},kind:`issues`}}function parsePullRequestEvent(n){let r=isObject(n.raw.pull_request)?n.raw.pull_request:null,i=typeof r?.number==`number`?r.number:void 0;return i===void 0?null:{...n,action:readAction(n.raw),baseRef:readPullRequestBaseRef(r),baseSha:readPullRequestBaseSha(r),conversation:{issueNumber:null,kind:`pull_request`,pullRequestNumber:i},defaultBranch:readPullRequestDefaultBranch(r),headRef:readPullRequestHeadRef(r),headSha:readPullRequestHeadSha(r),kind:`pull_request`,pullRequest:{action:readAction(n.raw),headSha:readPullRequestHeadSha(r),pullRequestNumber:i,raw:parseJsonObject(r)}}}function decodePayload(e,n){if(n?.includes(`application/x-www-form-urlencoded`)===!0){let n=new URLSearchParams(e).get(`payload`)??``;return parseJsonObject(JSON.parse(n))}return parseJsonObject(JSON.parse(e))}function normalizeRepository(t){if(!isObject(t))return null;let n=typeof t.full_name==`string`?t.full_name:``,[r=``,i=``]=n.split(`/`),a=isObject(t.owner)?t.owner:{},o=typeof a.login==`string`?a.login:r,s=typeof t.name==`string`?t.name:i,c=typeof t.id==`number`?t.id:0;return!o||!s?null:{fullName:n||`${o}/${s}`,id:c,name:s,owner:o,private:t.private===!0}}function normalizeUser(t){if(!isObject(t))return;let n=typeof t.login==`string`?t.login:``;if(n)return{htmlUrl:typeof t.html_url==`string`?t.html_url:void 0,id:typeof t.id==`number`?t.id:0,login:n,type:typeof t.type==`string`?t.type:`User`,url:typeof t.url==`string`?t.url:void 0}}function readInstallationId(t){if(isObject(t))return typeof t.id==`number`?t.id:void 0}function readAction(e){return typeof e.action==`string`?e.action:``}function readPullRequestHeadSha(t){let n=isObject(t?.head)?t.head:null;return typeof n?.sha==`string`?n.sha:null}function readPullRequestHeadRef(t){let n=isObject(t?.head)?t.head:null;return typeof n?.ref==`string`?n.ref:null}function readPullRequestBaseRef(t){let n=isObject(t?.base)?t.base:null;return typeof n?.ref==`string`?n.ref:null}function readPullRequestBaseSha(t){let n=isObject(t?.base)?t.base:null;return typeof n?.sha==`string`?n.sha:null}function readPullRequestDefaultBranch(t){let n=isObject(t?.base)?t.base:null,r=isObject(n?.repo)?n.repo:null;return typeof r?.default_branch==`string`?r.default_branch:null}function isIgnoredGitHubComment(e,t,n){if(e.includes(`<!-- ash:github:`))return!0;if(t===void 0)return!1;if(t.type===`Bot`)return!0;let r=n?`${n}[bot]`.toLowerCase():``;return r.length>0&&t.login.toLowerCase()===r}function requiredNumber(e,t){if(typeof e==`number`&&Number.isFinite(e))return e;throw Error(`githubContinuationToken requires ${t}.`)}function escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/gu,`\\$&`)}export{extractGitHubCommentTrigger,formatGitHubContextBlock,githubContinuationToken,parseGitHubWebhookEvent,prependGitHubContext,shouldDispatchGitHubComment};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { GitHubApiError, type GitHubApiMethod, type GitHubApiOptions, type GitHubApiResponse, type GitHubJsonObject, type GitHubPostedComment, type GitHubReactionContent, } from "#public/channels/github/api.js";
|
|
2
|
+
export { type GitHubHandle, type GitHubThread } from "#public/channels/github/binding.js";
|
|
3
|
+
export { type GitHubAppId, type GitHubChannelCredentials, type GitHubInstallationToken, type GitHubPrivateKey, type GitHubWebhookSecret, } from "#public/channels/github/auth.js";
|
|
4
|
+
export { defaultGitHubAuth } from "#public/channels/github/defaults.js";
|
|
5
|
+
export { type GitHubComment, type GitHubConversationKind, type GitHubConversationRef, type GitHubDelivery, type GitHubIssueAction, type GitHubIssueEvent, type GitHubPullRequestAction, type GitHubPullRequestEvent, type GitHubRepositoryRef, type GitHubUser, } from "#public/channels/github/inbound.js";
|
|
6
|
+
export { githubChannel, type GitHubChannel, type GitHubChannelConfig, type GitHubChannelEvents, type GitHubEventContext, type GitHubInboundContext, type GitHubInboundResult, type GitHubInboundResultOrPromise, type GitHubProgressConfig, type GitHubReceiveTarget, } from "#public/channels/github/githubChannel.js";
|
|
7
|
+
export { GITHUB_DEFAULT_EXCLUDED_DIFF_FILES, type GitHubPullRequestContextConfig, } from "#public/channels/github/pr-context.js";
|
|
8
|
+
export { type GitHubChannelState } from "#public/channels/github/state.js";
|
|
9
|
+
export { type GitHubWebhookVerifier } from "#public/channels/github/verify.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{GitHubApiError}from"#public/channels/github/api.js";import{GITHUB_DEFAULT_EXCLUDED_DIFF_FILES}from"#public/channels/github/pr-context.js";import{defaultGitHubAuth}from"#public/channels/github/defaults.js";import{githubChannel}from"#public/channels/github/githubChannel.js";export{GITHUB_DEFAULT_EXCLUDED_DIFF_FILES,GitHubApiError,defaultGitHubAuth,githubChannel};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Maximum body length accepted by GitHub issue and pull-request comments. */
|
|
2
|
+
export declare const GITHUB_COMMENT_BODY_MAX_LENGTH = 65536;
|
|
3
|
+
/** Splits a long comment body into GitHub-sized comment bodies. */
|
|
4
|
+
export declare function splitGitHubCommentBody(body: string, maxLength?: number): readonly string[];
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const GITHUB_COMMENT_BODY_MAX_LENGTH=65536;function splitGitHubCommentBody(t,n=GITHUB_COMMENT_BODY_MAX_LENGTH){if(t.length<=n)return[t];let r=[],i=t;for(;i.length>n;){let e=findCommentSplitIndex(i,n);r.push(i.slice(0,e).trimEnd()),i=i.slice(e).trimStart()}return i.length>0&&r.push(i),r}function findCommentSplitIndex(e,t){let n=e.lastIndexOf(`
|
|
2
|
+
`,t);if(n>t*.5)return n;let r=e.lastIndexOf(` `,t);return r>t*.5?r:t}export{GITHUB_COMMENT_BODY_MAX_LENGTH,splitGitHubCommentBody};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type GitHubApiOptions } from "#public/channels/github/api.js";
|
|
2
|
+
import type { GitHubChannelCredentials } from "#public/channels/github/auth.js";
|
|
3
|
+
/**
|
|
4
|
+
* Built-in glob patterns excluded from the diff loaded into model context.
|
|
5
|
+
*
|
|
6
|
+
* These files are large and generated; their patch text rarely helps the model
|
|
7
|
+
* and burns context budget. They are still listed with their stats so the agent
|
|
8
|
+
* knows they changed, and the full file is always available from the checkout.
|
|
9
|
+
*/
|
|
10
|
+
export declare const GITHUB_DEFAULT_EXCLUDED_DIFF_FILES: readonly string[];
|
|
11
|
+
/** Controls the pull-request diff injected into GitHub-triggered turns. */
|
|
12
|
+
export interface GitHubPullRequestContextConfig {
|
|
13
|
+
/**
|
|
14
|
+
* Additional glob patterns excluded from the diff loaded into model context.
|
|
15
|
+
* Extends the built-in {@link GITHUB_DEFAULT_EXCLUDED_DIFF_FILES} list — it
|
|
16
|
+
* does not replace it. Excluded files are still listed with their stats; only
|
|
17
|
+
* the patch body is omitted.
|
|
18
|
+
*/
|
|
19
|
+
readonly excludedFiles?: readonly string[];
|
|
20
|
+
}
|
|
21
|
+
/** Input for building one-shot model context for a pull request. */
|
|
22
|
+
export interface GitHubPullRequestContextInput {
|
|
23
|
+
readonly api?: GitHubApiOptions;
|
|
24
|
+
readonly config?: GitHubPullRequestContextConfig;
|
|
25
|
+
readonly credentials?: GitHubChannelCredentials;
|
|
26
|
+
readonly installationId?: number;
|
|
27
|
+
readonly owner: string;
|
|
28
|
+
readonly pullRequestNumber: number | null;
|
|
29
|
+
readonly repo: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Builds bounded, one-shot pull-request background for a GitHub turn: PR
|
|
33
|
+
* metadata plus the changed-file diff (noisy files excluded from the patch).
|
|
34
|
+
*
|
|
35
|
+
* The returned strings are intended for `SendPayload.context`; each is appended
|
|
36
|
+
* as a `role: "user"` message to session history before the delivery message.
|
|
37
|
+
*/
|
|
38
|
+
export declare function buildGitHubPullRequestContext(input: GitHubPullRequestContextInput): Promise<readonly string[] | undefined>;
|
|
39
|
+
/** Merges channel-generated PR context before hook-provided context. */
|
|
40
|
+
export declare function mergeGitHubContext(input: {
|
|
41
|
+
readonly github?: readonly string[];
|
|
42
|
+
readonly hook?: readonly string[];
|
|
43
|
+
}): readonly string[] | undefined;
|
|
44
|
+
/** Returns true when a file path matches any of the provided glob patterns. */
|
|
45
|
+
export declare function fileMatchesAnyGlob(filename: string, patterns: readonly string[]): boolean;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{getGitHubPullRequest,listGitHubPullRequestFiles}from"#public/channels/github/api.js";const MAX_PATCH_BYTES=2e4,GITHUB_DEFAULT_EXCLUDED_DIFF_FILES=[`**/pnpm-lock.yaml`,`**/package-lock.json`,`**/npm-shrinkwrap.json`,`**/yarn.lock`,`**/bun.lockb`,`**/Cargo.lock`,`**/go.sum`,`**/poetry.lock`,`**/Pipfile.lock`,`**/uv.lock`,`**/composer.lock`,`**/Gemfile.lock`,`**/*.min.js`,`**/*.min.css`,`**/*.map`,`**/*.snap`];async function buildGitHubPullRequestContext(n){if(n.pullRequestNumber===null)return;let i=renderPullRequestMetadata(await getGitHubPullRequest({api:n.api,credentials:n.credentials,installationId:n.installationId,owner:n.owner,pullRequestNumber:n.pullRequestNumber,repo:n.repo})),a=await listGitHubPullRequestFiles({api:n.api,credentials:n.credentials,installationId:n.installationId,owner:n.owner,perPage:50,pullRequestNumber:n.pullRequestNumber,repo:n.repo}),o=[...GITHUB_DEFAULT_EXCLUDED_DIFF_FILES,...n.config?.excludedFiles??[]];return i.push(``,...renderPullRequestFiles(a,o)),[[`GitHub pull request context for the current turn. `,`Use this as background for the user's GitHub comment.`,``,i.join(`
|
|
2
|
+
`)].join(`
|
|
3
|
+
`)]}function mergeGitHubContext(e){let t=e.github??[],n=e.hook??[];if(!(t.length===0&&n.length===0))return[...t,...n]}function renderPullRequestMetadata(e){return[`<github_pull_request>`,`number: ${e.number}`,`title: ${e.title}`,`state: ${e.state??`unknown`}`,`draft: ${e.draft?`true`:`false`}`,...e.author?.login?[`author: ${e.author.login}`]:[],...e.htmlUrl?[`url: ${e.htmlUrl}`]:[],...e.base.ref?[`base_ref: ${e.base.ref}`]:[],...e.base.sha?[`base_sha: ${e.base.sha}`]:[],...e.head.ref?[`head_ref: ${e.head.ref}`]:[],...e.head.sha?[`head_sha: ${e.head.sha}`]:[],...e.mergeable===null||e.mergeable===void 0?[]:[`mergeable: ${e.mergeable?`true`:`false`}`],...e.changedFiles===void 0?[]:[`changed_files: ${e.changedFiles}`],...e.additions===void 0?[]:[`additions: ${e.additions}`],...e.deletions===void 0?[]:[`deletions: ${e.deletions}`],...e.body?[``,`body:`,indent(truncateText(e.body,4e3))]:[],`</github_pull_request>`]}function renderPullRequestFiles(e,t){if(e.length===0)return[`<github_pull_request_files>`,`none`,`</github_pull_request_files>`];let r=[`<github_pull_request_files>`],i=MAX_PATCH_BYTES,a=!1;for(let n of e){if(r.push(renderFileSummary(n)),fileMatchesAnyGlob(n.filename,t)){r.push(` patch omitted (excluded)`);continue}if(n.patch===void 0)continue;if(i<=0){a=!0;continue}let e=truncateByBytes(n.patch,i);r.push(`patch:`,indent(e.text)),i-=e.bytes,e.truncated&&(a=!0,i=0)}return a&&r.push(``,`patches_truncated: true`,`max_patch_bytes: ${MAX_PATCH_BYTES}`),r.push(`</github_pull_request_files>`),r}function renderFileSummary(e){let t=[e.status??`modified`,e.additions===void 0?void 0:`+${e.additions}`,e.deletions===void 0?void 0:`-${e.deletions}`].filter(e=>e!==void 0);return`- ${e.filename}${t.length>0?` (${t.join(`, `)})`:``}`}function fileMatchesAnyGlob(e,t){return t.some(t=>globToRegExp(t).test(e))}function globToRegExp(e){let t=``;for(let n=0;n<e.length;n+=1){let r=e.charAt(n);r===`*`?e[n+1]===`*`?(t+=`.*`,n+=1,e[n+1]===`/`&&(n+=1)):t+=`[^/]*`:`\\^$.|?+()[]{}`.includes(r)?t+=`\\${r}`:t+=r}return RegExp(`^${t}$`,`u`)}function truncateByBytes(e,t){let n=new TextEncoder().encode(e);return n.byteLength<=t?{bytes:n.byteLength,text:e,truncated:!1}:{bytes:t,text:`${new TextDecoder().decode(n.slice(0,t))}\n[truncated]`,truncated:!0}}function truncateText(e,t){return e.length<=t?e:`${e.slice(0,t)}\n[truncated]`}function indent(e){return e.split(`
|
|
4
|
+
`).map(e=>` ${e}`).join(`
|
|
5
|
+
`)}export{GITHUB_DEFAULT_EXCLUDED_DIFF_FILES,buildGitHubPullRequestContext,fileMatchesAnyGlob,mergeGitHubContext};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type GitHubConversationKind, type GitHubConversationRef, type GitHubIssueCommentEvent, type GitHubIssueWebhookEvent, type GitHubPullRequestReviewCommentEvent, type GitHubPullRequestWebhookEvent } from "#public/channels/github/inbound.js";
|
|
2
|
+
/** JSON-serializable GitHub channel state. */
|
|
3
|
+
export interface GitHubChannelState {
|
|
4
|
+
baseRef: string | null;
|
|
5
|
+
baseSha: string | null;
|
|
6
|
+
checkoutPath: string | null;
|
|
7
|
+
conversationKind: GitHubConversationKind;
|
|
8
|
+
defaultBranch: string | null;
|
|
9
|
+
headRef: string | null;
|
|
10
|
+
headSha: string | null;
|
|
11
|
+
installationId: number | null;
|
|
12
|
+
issueNumber: number | null;
|
|
13
|
+
owner: string;
|
|
14
|
+
pullRequestNumber: number | null;
|
|
15
|
+
repo: string;
|
|
16
|
+
repositoryId: number;
|
|
17
|
+
reviewCommentId: number | null;
|
|
18
|
+
reviewThreadRootCommentId: number | null;
|
|
19
|
+
triggeringCommentId: number | null;
|
|
20
|
+
triggeringUserLogin: string | null;
|
|
21
|
+
}
|
|
22
|
+
/** Minimal receive target needed to seed GitHub channel state. */
|
|
23
|
+
export interface GitHubReceiveStateTarget {
|
|
24
|
+
readonly installationId?: number;
|
|
25
|
+
readonly issueNumber?: number;
|
|
26
|
+
readonly pullRequestNumber?: number;
|
|
27
|
+
}
|
|
28
|
+
/** Initial empty GitHub channel state. */
|
|
29
|
+
export declare function initialGitHubState(): GitHubChannelState;
|
|
30
|
+
/** Builds state for an issue or PR timeline comment. */
|
|
31
|
+
export declare function stateFromIssueCommentEvent(event: GitHubIssueCommentEvent): GitHubChannelState;
|
|
32
|
+
/** Builds state for an inline pull-request review comment. */
|
|
33
|
+
export declare function stateFromPullRequestReviewCommentEvent(event: GitHubPullRequestReviewCommentEvent): GitHubChannelState;
|
|
34
|
+
/** Builds state for an issue event hook dispatch. */
|
|
35
|
+
export declare function stateFromIssueEvent(event: GitHubIssueWebhookEvent): GitHubChannelState;
|
|
36
|
+
/** Builds state for a pull-request event hook dispatch. */
|
|
37
|
+
export declare function stateFromPullRequestEvent(event: GitHubPullRequestWebhookEvent): GitHubChannelState;
|
|
38
|
+
/** Builds state for proactive `receive()` calls. */
|
|
39
|
+
export declare function stateFromReceiveTarget(input: {
|
|
40
|
+
readonly target: GitHubReceiveStateTarget;
|
|
41
|
+
readonly owner: string;
|
|
42
|
+
readonly repo: string;
|
|
43
|
+
readonly repositoryId: number;
|
|
44
|
+
}): GitHubChannelState;
|
|
45
|
+
/** Reconstructs the channel-local GitHub conversation reference from state. */
|
|
46
|
+
export declare function conversationFromState(state: GitHubChannelState): GitHubConversationRef;
|
|
47
|
+
/** Builds the channel-local continuation token from durable state. */
|
|
48
|
+
export declare function continuationTokenFromState(state: GitHubChannelState): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{githubContinuationToken}from"#public/channels/github/inbound.js";function initialGitHubState(){return{baseRef:null,baseSha:null,checkoutPath:null,conversationKind:`issue`,defaultBranch:null,headRef:null,headSha:null,installationId:null,issueNumber:null,owner:``,pullRequestNumber:null,repo:``,repositoryId:0,reviewCommentId:null,reviewThreadRootCommentId:null,triggeringCommentId:null,triggeringUserLogin:null}}function stateFromIssueCommentEvent(e){return{...initialGitHubState(),baseRef:e.baseRef,baseSha:e.baseSha,conversationKind:e.conversation.kind,defaultBranch:e.defaultBranch,headRef:e.headRef,headSha:e.headSha,installationId:e.installationId??null,issueNumber:e.comment.issueNumber,owner:e.repository.owner,pullRequestNumber:e.comment.pullRequestNumber,repo:e.repository.name,repositoryId:e.repository.id,triggeringCommentId:e.comment.id,triggeringUserLogin:e.sender.login}}function stateFromPullRequestReviewCommentEvent(e){return{...initialGitHubState(),baseRef:e.baseRef,baseSha:e.baseSha,conversationKind:`review_thread`,defaultBranch:e.defaultBranch,headRef:e.headRef,headSha:e.headSha,installationId:e.installationId??null,owner:e.repository.owner,pullRequestNumber:e.comment.pullRequestNumber,repo:e.repository.name,repositoryId:e.repository.id,reviewCommentId:e.comment.id,reviewThreadRootCommentId:e.comment.reviewThreadRootCommentId,triggeringCommentId:e.comment.id,triggeringUserLogin:e.sender.login}}function stateFromIssueEvent(e){return{...initialGitHubState(),conversationKind:`issue`,installationId:e.installationId??null,issueNumber:e.issue.issueNumber,owner:e.repository.owner,repo:e.repository.name,repositoryId:e.repository.id,triggeringUserLogin:e.sender.login}}function stateFromPullRequestEvent(e){return{...initialGitHubState(),baseRef:e.baseRef,baseSha:e.baseSha,conversationKind:`pull_request`,defaultBranch:e.defaultBranch,headRef:e.headRef,headSha:e.headSha,installationId:e.installationId??null,issueNumber:e.pullRequest.pullRequestNumber,owner:e.repository.owner,pullRequestNumber:e.pullRequest.pullRequestNumber,repo:e.repository.name,repositoryId:e.repository.id,triggeringUserLogin:e.sender.login}}function stateFromReceiveTarget(e){let{target:t}=e,n=t.pullRequestNumber===void 0?`issue`:`pull_request`;return{...initialGitHubState(),conversationKind:n,installationId:t.installationId??null,issueNumber:n===`issue`?t.issueNumber??null:t.pullRequestNumber??null,owner:e.owner,pullRequestNumber:t.pullRequestNumber??null,repo:e.repo,repositoryId:e.repositoryId}}function conversationFromState(e){return{issueNumber:e.issueNumber,kind:e.conversationKind,pullRequestNumber:e.pullRequestNumber}}function continuationTokenFromState(t){return githubContinuationToken({conversationKind:t.conversationKind,issueNumber:t.issueNumber,pullRequestNumber:t.pullRequestNumber,repositoryId:t.repositoryId,reviewThreadRootCommentId:t.reviewThreadRootCommentId})}export{continuationTokenFromState,conversationFromState,initialGitHubState,stateFromIssueCommentEvent,stateFromIssueEvent,stateFromPullRequestEvent,stateFromPullRequestReviewCommentEvent,stateFromReceiveTarget};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type GitHubWebhookSecret } from "#public/channels/github/auth.js";
|
|
2
|
+
/**
|
|
3
|
+
* Caller-supplied inbound webhook verifier. Used as an alternative to
|
|
4
|
+
* HMAC verification — e.g. Connect supplies a verifier that authenticates
|
|
5
|
+
* Connect-forwarded webhooks with Vercel OIDC instead of GitHub's webhook
|
|
6
|
+
* secret.
|
|
7
|
+
*
|
|
8
|
+
* Contract (matches the other channels' `webhookVerifier`):
|
|
9
|
+
*
|
|
10
|
+
* - **Throw / reject** → the channel responds 401 to GitHub.
|
|
11
|
+
* - **Return a falsy value** (`null` / `undefined` / `false` / `""` / `0`)
|
|
12
|
+
* → the channel responds 401 to GitHub. This lets verifiers signal
|
|
13
|
+
* rejection without throwing — e.g. Connect's `vercelOidc()` returns
|
|
14
|
+
* `null` on a failed OIDC check.
|
|
15
|
+
* - **Return a truthy non-string value** → verification accepted.
|
|
16
|
+
* - **Return a string** → verification accepted, and the string replaces
|
|
17
|
+
* the raw body for downstream parsing.
|
|
18
|
+
*/
|
|
19
|
+
export type GitHubWebhookVerifier = (request: Request, body: string) => unknown | Promise<unknown>;
|
|
20
|
+
/** Options for {@link verifyGitHubRequest}. */
|
|
21
|
+
export interface GitHubVerifyOptions {
|
|
22
|
+
readonly webhookSecret?: GitHubWebhookSecret;
|
|
23
|
+
readonly webhookVerifier?: GitHubWebhookVerifier;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Verifies a GitHub webhook request and returns its raw body. The raw body is
|
|
27
|
+
* required because GitHub signs the exact bytes it delivered.
|
|
28
|
+
*
|
|
29
|
+
* When a {@link GitHubWebhookVerifier} is supplied, it replaces the built-in
|
|
30
|
+
* HMAC check: GitHub's webhook secret is never read and the verifier owns the
|
|
31
|
+
* accept/reject decision.
|
|
32
|
+
*/
|
|
33
|
+
export declare function verifyGitHubRequest(request: Request, options: GitHubVerifyOptions): Promise<string>;
|
|
34
|
+
/** Signs a raw GitHub webhook body for tests and local fixtures. */
|
|
35
|
+
export declare function signGitHubWebhookBody(body: string, secret: string): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createLogger}from"#internal/logging.js";import{createHmac,timingSafeEqual}from"node:crypto";import{resolveGitHubWebhookSecret}from"#public/channels/github/auth.js";const log=createLogger(`github.verify`);async function verifyGitHubRequest(e,t){let n=await e.text();if(t.webhookVerifier!==void 0){let r=await t.webhookVerifier(e,n);if(!r)throw Error(`githubChannel: inbound webhook verifier rejected the request.`);return typeof r==`string`?r:n}let i=await resolveGitHubWebhookSecret(t.webhookSecret),a=e.headers.get(`x-hub-signature-256`)??``;if(!a)throw Error(`githubChannel: inbound request missing X-Hub-Signature-256.`);if(!constantTimeCompare(signGitHubWebhookBody(n,i),a))throw Error(`githubChannel: inbound request signature mismatch.`);return n}function signGitHubWebhookBody(e,n){return`sha256=${createHmac(`sha256`,n).update(e).digest(`hex`)}`}function constantTimeCompare(e,t){if(e.length!==t.length)return!1;try{return timingSafeEqual(Buffer.from(e),Buffer.from(t))}catch(e){return log.debug(`timingSafeEqual threw`,{error:e}),!1}}export{signGitHubWebhookBody,verifyGitHubRequest};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { Optional } from "#shared/optional.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { SandboxDefinitionWithBootstrap as SharedSandboxDefinitionWithBootstrap, SandboxDefinitionWithoutBootstrap as SharedSandboxDefinitionWithoutBootstrap } from "#shared/sandbox-definition.js";
|
|
3
3
|
export type { SandboxCommandResult, SandboxProcess, SandboxReadBinaryFileOptions, SandboxReadFileOptions, SandboxRemovePathOptions, SandboxReadTextFileOptions, SandboxRunOptions, SandboxSession, SandboxSpawnOptions, SandboxWriteBinaryFileOptions, SandboxWriteFileOptions, SandboxWriteTextFileOptions, } from "#shared/sandbox-session.js";
|
|
4
|
-
export type { SandboxBootstrapUseFn, SandboxSessionUseFn, SandboxBootstrapContext, SandboxSessionContext, } from "#shared/sandbox-definition.js";
|
|
5
|
-
export type SandboxDefinition<BO = Record<string, never>, SO = Record<string, never>> = Optional<
|
|
4
|
+
export type { SandboxBootstrapUseFn, SandboxRevalidationKeyFn, SandboxSessionUseFn, SandboxBootstrapContext, SandboxSessionContext, } from "#shared/sandbox-definition.js";
|
|
5
|
+
export type SandboxDefinition<BO = Record<string, never>, SO = Record<string, never>> = Optional<SharedSandboxDefinitionWithBootstrap<BO, SO>, "backend"> | Optional<SharedSandboxDefinitionWithoutBootstrap<BO, SO>, "backend">;
|
|
6
6
|
/**
|
|
7
7
|
* Defines a sandbox configuration.
|
|
8
8
|
*/
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Sandbox authoring helpers for `agent/sandbox.ts` (or
|
|
3
3
|
* `agent/sandbox/sandbox.ts` when paired with a `workspace/` folder).
|
|
4
4
|
*/
|
|
5
|
-
export { defineSandbox, type SandboxBootstrapContext, type SandboxBootstrapUseFn, type SandboxCommandResult, type SandboxDefinition, type SandboxProcess, type SandboxReadBinaryFileOptions, type SandboxReadFileOptions, type SandboxReadTextFileOptions, type SandboxRunOptions, type SandboxSession, type SandboxSpawnOptions, type SandboxSessionContext, type SandboxSessionUseFn, type SandboxWriteBinaryFileOptions, type SandboxWriteFileOptions, type SandboxWriteTextFileOptions, } from "#public/definitions/sandbox.js";
|
|
5
|
+
export { defineSandbox, type SandboxBootstrapContext, type SandboxBootstrapUseFn, type SandboxCommandResult, type SandboxDefinition, type SandboxProcess, type SandboxReadBinaryFileOptions, type SandboxReadFileOptions, type SandboxReadTextFileOptions, type SandboxRevalidationKeyFn, type SandboxRunOptions, type SandboxSession, type SandboxSpawnOptions, type SandboxSessionContext, type SandboxSessionUseFn, type SandboxWriteBinaryFileOptions, type SandboxWriteFileOptions, type SandboxWriteTextFileOptions, } from "#public/definitions/sandbox.js";
|
|
6
6
|
export type { SandboxBackend, SandboxBackendCreateInput, SandboxBackendHandle, SandboxBackendPrewarmInput, SandboxBackendRuntimeContext, SandboxBackendSessionState, SandboxSeedFile, } from "#public/definitions/sandbox-backend.js";
|
|
7
7
|
export type { SandboxNetworkPolicy } from "#shared/sandbox-network-policy.js";
|
|
8
8
|
export { SandboxTemplateNotProvisionedError } from "#public/definitions/sandbox-backend.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{expectObjectRecord}from"#internal/authored-module.js";import{toErrorMessage}from"#shared/errors.js";import{lazyBackend}from"#execution/sandbox/lazy-backend.js";import{ResolveAgentError,loadResolvedModuleExport}from"#runtime/resolve-helpers.js";import{defaultBackend}from"#public/sandbox/backends/default.js";async function resolveSandboxDefinition(n,i,a){try{let t=expectObjectRecord(await loadResolvedModuleExport({definition:n,kindLabel:`sandbox`,moduleMap:i,nodeId:a}),`Expected the sandbox export "${n.exportName??`default`}" from "${n.logicalPath}" to return an object.`);return{backend:resolveBackend(t.backend,n.logicalPath),bootstrap:t.bootstrap,description:n.description,exportName:n.exportName,logicalPath:n.logicalPath,onSession:t.onSession,sourceId:n.sourceId,sourceKind:`module`}}catch(e){throw e instanceof ResolveAgentError?e:new ResolveAgentError(`Failed to attach the sandbox lifecycle handlers from "${n.logicalPath}": ${toErrorMessage(e)}`,{logicalPath:n.logicalPath,sourceId:n.sourceId})}}function resolveBackend(e,t){if(e===void 0)return defaultBackend();if(typeof e==`function`)return lazyBackend(e);if(typeof e!=`object`||!e)throw new ResolveAgentError(`Sandbox "${t}" exposed a non-object "backend" field. Use vercelBackend(), localBackend(), another factory that returns a SandboxBackend value, or a zero-arg callback returning one.`,{logicalPath:t});let r=e;if(typeof r.name!=`string`||r.name.length===0)throw new ResolveAgentError(`Sandbox "${t}" backend is missing a non-empty string "name" identifier.`,{logicalPath:t});if(typeof r.create!=`function`)throw new ResolveAgentError(`Sandbox "${t}" backend is missing a "create" function.`,{logicalPath:t});return r}export{resolveSandboxDefinition};
|
|
1
|
+
import{expectObjectRecord}from"#internal/authored-module.js";import{toErrorMessage}from"#shared/errors.js";import{lazyBackend}from"#execution/sandbox/lazy-backend.js";import{ResolveAgentError,loadResolvedModuleExport}from"#runtime/resolve-helpers.js";import{defaultBackend}from"#public/sandbox/backends/default.js";async function resolveSandboxDefinition(n,i,a){try{let t=expectObjectRecord(await loadResolvedModuleExport({definition:n,kindLabel:`sandbox`,moduleMap:i,nodeId:a}),`Expected the sandbox export "${n.exportName??`default`}" from "${n.logicalPath}" to return an object.`);return{backend:resolveBackend(t.backend,n.logicalPath),bootstrap:t.bootstrap,description:n.description,exportName:n.exportName,logicalPath:n.logicalPath,onSession:t.onSession,revalidationKey:n.revalidationKey,sourceHash:n.sourceHash,sourceId:n.sourceId,sourceKind:`module`}}catch(e){throw e instanceof ResolveAgentError?e:new ResolveAgentError(`Failed to attach the sandbox lifecycle handlers from "${n.logicalPath}": ${toErrorMessage(e)}`,{logicalPath:n.logicalPath,sourceId:n.sourceId})}}function resolveBackend(e,t){if(e===void 0)return defaultBackend();if(typeof e==`function`)return lazyBackend(e);if(typeof e!=`object`||!e)throw new ResolveAgentError(`Sandbox "${t}" exposed a non-object "backend" field. Use vercelBackend(), localBackend(), another factory that returns a SandboxBackend value, or a zero-arg callback returning one.`,{logicalPath:t});let r=e;if(typeof r.name!=`string`||r.name.length===0)throw new ResolveAgentError(`Sandbox "${t}" backend is missing a non-empty string "name" identifier.`,{logicalPath:t});if(typeof r.create!=`function`)throw new ResolveAgentError(`Sandbox "${t}" backend is missing a "create" function.`,{logicalPath:t});return r}export{resolveSandboxDefinition};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{realpath}from"node:fs/promises";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{createHash}from"node:crypto";import{getRuntimeCompiledArtifactsAppRoot,getRuntimeCompiledArtifactsCacheKey}from"#runtime/compiled-artifacts-source.js";import{loadCompileMetadata}from"#runtime/loaders/compile-metadata.js";async function createRuntimeSandboxKeys(e){return{sessionKey:await createRuntimeSandboxSessionKey(e),templateKey:await createRuntimeSandboxTemplateKey(e)}}async function createRuntimeSandboxTemplateKey(e){if(e.templatePlan.kind===`none`)return null;let n=await resolveRuntimeSandboxScope({backendName:e.backendName,compiledArtifactsSource:e.compiledArtifactsSource,scopeKind:e.templatePlan.kind===`source-graph`?`deployment`:`stable`}),r=await resolveRuntimeSandboxVersionHash({compiledArtifactsSource:e.compiledArtifactsSource,nodeId:e.nodeId,sourceId:e.sourceId,templatePlan:e.templatePlan}),i=createStableHash(`${resolveInstalledPackageInfo().version}:
|
|
1
|
+
import{realpath}from"node:fs/promises";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{createHash}from"node:crypto";import{getRuntimeCompiledArtifactsAppRoot,getRuntimeCompiledArtifactsCacheKey}from"#runtime/compiled-artifacts-source.js";import{loadCompileMetadata}from"#runtime/loaders/compile-metadata.js";async function createRuntimeSandboxKeys(e){return{sessionKey:await createRuntimeSandboxSessionKey(e),templateKey:await createRuntimeSandboxTemplateKey(e)}}async function createRuntimeSandboxTemplateKey(e){if(e.templatePlan.kind===`none`)return null;let n=await resolveRuntimeSandboxScope({backendName:e.backendName,compiledArtifactsSource:e.compiledArtifactsSource,scopeKind:e.templatePlan.kind===`source-graph`?`deployment`:`stable`}),r=await resolveRuntimeSandboxVersionHash({compiledArtifactsSource:e.compiledArtifactsSource,nodeId:e.nodeId,sourceId:e.sourceId,templatePlan:e.templatePlan}),i=createStableHash(`${resolveInstalledPackageInfo().version}:5:${r}`).slice(0,20);return sanitizeRuntimeSandboxKey(`ash-sbx-tpl-${e.backendName}-${n}-${i}`)}async function createRuntimeSandboxSessionKey(e){let t=await resolveRuntimeSandboxScope({backendName:e.backendName,compiledArtifactsSource:e.compiledArtifactsSource,scopeKind:`deployment`}),n=sanitizeRuntimeSandboxKey(e.nodeId);return sanitizeRuntimeSandboxKey(`ash-sbx-ses-${e.backendName}-${t}-${e.sessionId}-${n}`)}async function resolveRuntimeSandboxScope(t){if(t.backendName===`vercel`){if(t.scopeKind===`stable`){let e=resolveVercelProjectScope();if(e!==void 0)return createStableHash(e).slice(0,16)}let e=process.env.VERCEL_DEPLOYMENT_ID?.trim();if(e!==void 0&&e.length>0)return createStableHash(e).slice(0,16)}let n=getRuntimeCompiledArtifactsAppRoot(t.compiledArtifactsSource);return n===void 0?createStableHash(getRuntimeCompiledArtifactsCacheKey(t.compiledArtifactsSource)).slice(0,16):createStableHash(await realpath(n)).slice(0,16)}async function resolveRuntimeSandboxVersionHash(e){if(e.templatePlan.kind===`bootstrap`){let t=e.templatePlan.contentHash??await resolveSourceGraphHash(e.compiledArtifactsSource);return createStableHash(`bootstrap:${e.templatePlan.revalidationKey??``}:${e.templatePlan.sourceHash}:${t}:${e.nodeId}:${e.sourceId}`)}return e.templatePlan.kind===`workspace-content`?createStableHash(`workspace-content:${e.templatePlan.contentHash??await resolveSourceGraphHash(e.compiledArtifactsSource)}:${e.nodeId}:${e.sourceId}`):createStableHash(`source-graph:${await resolveSourceGraphHash(e.compiledArtifactsSource)}:${e.nodeId}:${e.sourceId}`)}async function resolveSourceGraphHash(e){return(await loadCompileMetadata({compiledArtifactsSource:e}))?.discovery.sourceGraphHash??getRuntimeCompiledArtifactsCacheKey(e)}function resolveVercelProjectScope(){let e=process.env.VERCEL_PROJECT_ID?.trim();if(e===void 0||e.length===0)return;let t=process.env.VERCEL_TEAM_ID?.trim();return t===void 0||t.length===0?`vercel-project:${e}`:`vercel-project:${t}:${e}`}function createStableHash(e){return createHash(`sha256`).update(e).digest(`hex`)}function sanitizeRuntimeSandboxKey(e){return e.replaceAll(/[^a-zA-Z0-9._-]+/g,`-`).slice(0,120)}export{createRuntimeSandboxKeys,createRuntimeSandboxTemplateKey};
|
|
@@ -9,6 +9,11 @@ export type RuntimeSandboxTemplatePlan = {
|
|
|
9
9
|
} | {
|
|
10
10
|
readonly contentHash?: string;
|
|
11
11
|
readonly kind: "workspace-content";
|
|
12
|
+
} | {
|
|
13
|
+
readonly contentHash?: string;
|
|
14
|
+
readonly kind: "bootstrap";
|
|
15
|
+
readonly revalidationKey?: string;
|
|
16
|
+
readonly sourceHash: string;
|
|
12
17
|
} | {
|
|
13
18
|
readonly kind: "source-graph";
|
|
14
19
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function createRuntimeSandboxTemplatePlan(e){
|
|
1
|
+
function createRuntimeSandboxTemplatePlan(e){if(e.definition.bootstrap!==void 0){if(e.definition.sourceHash===void 0)throw Error(`Sandbox "${e.definition.logicalPath}" defines bootstrap() but has no compiled sourceHash.`);return{contentHash:e.workspaceResourceRoot.contentHash,kind:`bootstrap`,revalidationKey:e.definition.revalidationKey,sourceHash:e.definition.sourceHash}}return e.workspaceResourceRoot.rootEntries.length===0?{kind:`none`}:{contentHash:e.workspaceResourceRoot.contentHash,kind:`workspace-content`}}export{createRuntimeSandboxTemplatePlan};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{RuntimeRegistry,RuntimeRegistryError}from"#internal/runtime-registry.js";const SUBAGENT_TOOL_INPUT_SCHEMA=Object.freeze({type:`object`,properties:Object.freeze({message:Object.freeze({type:`string`,description:`The message to send to the subagent. Provide all context the subagent needs to complete the task; the subagent does not see the parent's history.`})}),required:Object.freeze([`message`]),additionalProperties:!1});function createRuntimeSubagentRegistry(t){let n=[],r=new RuntimeRegistry(`subagent`,t.reservedToolNames??[]),i=new Map;for(let e of t.subagents){let t={logicalPath:e.logicalPath,sourceId:e.sourceId};if(i.has(e.nodeId))throw new RuntimeRegistryError(`subagent`,`Found multiple runtime subagents mapped to node id "${e.nodeId}".`,{...t,entryName:e.name});let a=createPreparedRuntimeSubagentTool(e),o={definition:e,prepared:a};r.register(e.name,o,{location:t,duplicateMessage:`Found multiple subagents named "${e.name}". Subagent names must be unique at runtime.`,reservedMessage:`Subagent "${e.name}" collides with another runtime-visible tool name.`}),n.push(a),i.set(e.nodeId,o)}return{preparedTools:n,subagentsByName:r.asMap(),subagentsByNodeId:i}}function createPreparedRuntimeSubagentTool(e){return{description:e.description,inputSchema:SUBAGENT_TOOL_INPUT_SCHEMA,kind:e.kind,logicalPath:e.logicalPath,name:e.name,nodeId:e.nodeId,outputSchema:e.kind===`remote`?e.outputSchema:void 0,sourceId:e.sourceId}}export{createRuntimeSubagentRegistry};
|
|
1
|
+
import{RuntimeRegistry,RuntimeRegistryError}from"#internal/runtime-registry.js";const SUBAGENT_TOOL_INPUT_SCHEMA=Object.freeze({type:`object`,properties:Object.freeze({message:Object.freeze({type:`string`,description:`The message to send to the subagent. Provide all context the subagent needs to complete the task; the subagent does not see the parent's history.`}),outputSchema:Object.freeze({type:`object`,description:`When provided, the subagent runs in task mode and must produce structured output matching this JSON Schema. The structured output becomes the tool result.`})}),required:Object.freeze([`message`]),additionalProperties:!1});function createRuntimeSubagentRegistry(t){let n=[],r=new RuntimeRegistry(`subagent`,t.reservedToolNames??[]),i=new Map;for(let e of t.subagents){let t={logicalPath:e.logicalPath,sourceId:e.sourceId};if(i.has(e.nodeId))throw new RuntimeRegistryError(`subagent`,`Found multiple runtime subagents mapped to node id "${e.nodeId}".`,{...t,entryName:e.name});let a=createPreparedRuntimeSubagentTool(e),o={definition:e,prepared:a};r.register(e.name,o,{location:t,duplicateMessage:`Found multiple subagents named "${e.name}". Subagent names must be unique at runtime.`,reservedMessage:`Subagent "${e.name}" collides with another runtime-visible tool name.`}),n.push(a),i.set(e.nodeId,o)}return{preparedTools:n,subagentsByName:r.asMap(),subagentsByNodeId:i}}function createPreparedRuntimeSubagentTool(e){return{description:e.description,inputSchema:SUBAGENT_TOOL_INPUT_SCHEMA,kind:e.kind,logicalPath:e.logicalPath,name:e.name,nodeId:e.nodeId,outputSchema:e.kind===`remote`?e.outputSchema:void 0,sourceId:e.sourceId}}export{createRuntimeSubagentRegistry};
|
|
@@ -19,7 +19,7 @@ import type { NamedSkillDefinition } from "#shared/skill-definition.js";
|
|
|
19
19
|
import type { InternalAgentDefinition } from "#shared/agent-definition.js";
|
|
20
20
|
import type { InternalToolDefinitionWithExecuteFn } from "#shared/tool-definition.js";
|
|
21
21
|
import type { SandboxBackend } from "#shared/sandbox-backend.js";
|
|
22
|
-
import type {
|
|
22
|
+
import type { SandboxBootstrapContext, SandboxSessionContext } from "#shared/sandbox-definition.js";
|
|
23
23
|
/**
|
|
24
24
|
* Runtime-owned source ref describing one additive config module import.
|
|
25
25
|
*/
|
|
@@ -86,7 +86,10 @@ export interface ResolvedConnectionDefinition extends ResolvedModuleSourceRef {
|
|
|
86
86
|
* `vercelBackend()` and `localBackend()` based on the current
|
|
87
87
|
* environment).
|
|
88
88
|
*/
|
|
89
|
-
export type ResolvedSandboxDefinition =
|
|
89
|
+
export type ResolvedSandboxDefinition = ResolvedModuleSourceRef & {
|
|
90
|
+
readonly bootstrap?: (input: SandboxBootstrapContext) => Promise<void> | void;
|
|
91
|
+
readonly revalidationKey?: string;
|
|
92
|
+
readonly sourceHash?: string;
|
|
90
93
|
/**
|
|
91
94
|
* Resolved backend value. The authored `SandboxDefinition.backend`
|
|
92
95
|
* accepts either a `SandboxBackend` or a `() => SandboxBackend`; by
|
|
@@ -96,6 +99,7 @@ export type ResolvedSandboxDefinition = Readonly<Omit<SandboxDefinition, "backen
|
|
|
96
99
|
*/
|
|
97
100
|
readonly backend: SandboxBackend;
|
|
98
101
|
readonly description?: string;
|
|
102
|
+
readonly onSession?: (input: SandboxSessionContext) => Promise<void> | void;
|
|
99
103
|
};
|
|
100
104
|
/**
|
|
101
105
|
* Runtime-owned authored tool definition resolved from a compiled module map.
|
|
@@ -10,6 +10,7 @@ export interface SandboxSessionContext<O = Record<string, never>> {
|
|
|
10
10
|
readonly ctx: SessionContext;
|
|
11
11
|
readonly use: SandboxSessionUseFn<O>;
|
|
12
12
|
}
|
|
13
|
+
export type SandboxRevalidationKeyFn = () => Promise<string> | string;
|
|
13
14
|
/**
|
|
14
15
|
* Public sandbox definition authored in `agent/sandbox.ts` (shorthand)
|
|
15
16
|
* or `agent/sandbox/sandbox.ts` (folder layout, when paired with an
|
|
@@ -23,7 +24,7 @@ export interface SandboxSessionContext<O = Record<string, never>> {
|
|
|
23
24
|
* `subagents/<name>/sandbox.ts` (or the folder form) and do not inherit
|
|
24
25
|
* their parent's sandbox (skill seeds differ per agent).
|
|
25
26
|
*/
|
|
26
|
-
|
|
27
|
+
interface SandboxDefinitionBase<BO = Record<string, never>, SO = Record<string, never>> {
|
|
27
28
|
/**
|
|
28
29
|
* Backend that runs this sandbox.
|
|
29
30
|
*
|
|
@@ -49,6 +50,25 @@ export interface SandboxDefinition<BO = Record<string, never>, SO = Record<strin
|
|
|
49
50
|
* specific backend regardless of environment.
|
|
50
51
|
*/
|
|
51
52
|
readonly backend: SandboxBackend<BO, SO> | (() => SandboxBackend<BO, SO>);
|
|
52
|
-
|
|
53
|
+
readonly description?: string;
|
|
53
54
|
onSession?(input: SandboxSessionContext<SO>): Promise<void> | void;
|
|
54
55
|
}
|
|
56
|
+
export interface SandboxDefinitionWithBootstrap<BO = Record<string, never>, SO = Record<string, never>> extends SandboxDefinitionBase<BO, SO> {
|
|
57
|
+
bootstrap(input: SandboxBootstrapContext<BO>): Promise<void> | void;
|
|
58
|
+
/**
|
|
59
|
+
* Optional build-time revalidation key for the reusable sandbox
|
|
60
|
+
* snapshot produced by {@link bootstrap}. Ash evaluates this
|
|
61
|
+
* function during compile/build, stores the resolved string in
|
|
62
|
+
* compiled artifacts, and uses that frozen value for both prewarm and
|
|
63
|
+
* runtime session create. Authored sandbox source and
|
|
64
|
+
* framework-managed seed contents are included automatically; provide
|
|
65
|
+
* this key only for external inputs that affect bootstrap output.
|
|
66
|
+
*/
|
|
67
|
+
readonly revalidationKey?: SandboxRevalidationKeyFn;
|
|
68
|
+
}
|
|
69
|
+
export interface SandboxDefinitionWithoutBootstrap<BO = Record<string, never>, SO = Record<string, never>> extends SandboxDefinitionBase<BO, SO> {
|
|
70
|
+
bootstrap?: undefined;
|
|
71
|
+
readonly revalidationKey?: never;
|
|
72
|
+
}
|
|
73
|
+
export type SandboxDefinition<BO = Record<string, never>, SO = Record<string, never>> = SandboxDefinitionWithBootstrap<BO, SO> | SandboxDefinitionWithoutBootstrap<BO, SO>;
|
|
74
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "experimental-ash",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.57.0",
|
|
4
4
|
"description": "Filesystem-first framework for durable backend AI agents that run anywhere.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-framework",
|
|
@@ -165,6 +165,11 @@
|
|
|
165
165
|
"import": "./dist/src/public/channels/slack/index.js",
|
|
166
166
|
"default": "./dist/src/public/channels/slack/index.js"
|
|
167
167
|
},
|
|
168
|
+
"./channels/github": {
|
|
169
|
+
"types": "./dist/src/public/channels/github/index.d.ts",
|
|
170
|
+
"import": "./dist/src/public/channels/github/index.js",
|
|
171
|
+
"default": "./dist/src/public/channels/github/index.js"
|
|
172
|
+
},
|
|
168
173
|
"./channels/discord": {
|
|
169
174
|
"types": "./dist/src/public/channels/discord/index.d.ts",
|
|
170
175
|
"import": "./dist/src/public/channels/discord/index.js",
|