@geminixiang/mikan 1.0.0-beta.7 → 1.0.0-beta.9
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 +37 -0
- package/dist/adapter.d.ts +1 -1
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js.map +1 -1
- package/dist/adapters/github/bot.d.ts +63 -0
- package/dist/adapters/github/bot.d.ts.map +1 -0
- package/dist/adapters/github/bot.js +566 -0
- package/dist/adapters/github/bot.js.map +1 -0
- package/dist/adapters/github/client.d.ts +76 -0
- package/dist/adapters/github/client.d.ts.map +1 -0
- package/dist/adapters/github/client.js +194 -0
- package/dist/adapters/github/client.js.map +1 -0
- package/dist/adapters/github/context.d.ts +9 -0
- package/dist/adapters/github/context.d.ts.map +1 -0
- package/dist/adapters/github/context.js +168 -0
- package/dist/adapters/github/context.js.map +1 -0
- package/dist/adapters/github/ids.d.ts +25 -0
- package/dist/adapters/github/ids.d.ts.map +1 -0
- package/dist/adapters/github/ids.js +39 -0
- package/dist/adapters/github/ids.js.map +1 -0
- package/dist/adapters/github/repo.d.ts +19 -0
- package/dist/adapters/github/repo.d.ts.map +1 -0
- package/dist/adapters/github/repo.js +58 -0
- package/dist/adapters/github/repo.js.map +1 -0
- package/dist/adapters/github/types.d.ts +111 -0
- package/dist/adapters/github/types.d.ts.map +1 -0
- package/dist/adapters/github/types.js +2 -0
- package/dist/adapters/github/types.js.map +1 -0
- package/dist/agent.d.ts +2 -2
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +10 -2
- package/dist/agent.js.map +1 -1
- package/dist/main.js +52 -2
- package/dist/main.js.map +1 -1
- package/dist/runtime/conversation-runtime.js +1 -1
- package/dist/runtime/conversation-runtime.js.map +1 -1
- package/dist/runtime/types.d.ts +3 -1
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/sessions/policy.d.ts.map +1 -1
- package/dist/sessions/policy.js +1 -0
- package/dist/sessions/policy.js.map +1 -1
- package/dist/tools/github-pr.d.ts +22 -0
- package/dist/tools/github-pr.d.ts.map +1 -0
- package/dist/tools/github-pr.js +53 -0
- package/dist/tools/github-pr.js.map +1 -0
- package/dist/tools/index.d.ts +2 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +4 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/types.d.ts +20 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/adapters/github/context.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ChatToolResult,\n ConversationMessage,\n ConversationResponder,\n MessagingInfo,\n} from \"../../adapter.js\";\nimport * as log from \"../../log.js\";\nimport { resolveChatSessionKey } from \"../../sessions/policy.js\";\nimport {\n createChatResponseErrorReporter,\n formatToolArgs,\n splitText,\n type ChatResponseErrorOperation,\n} from \"../shared.js\";\nimport {\n formatGithubContinuation,\n GITHUB_MAX_COMMENT_LENGTH,\n type GithubMessagingBot,\n} from \"./bot.js\";\nimport { parseGithubConversationId } from \"./ids.js\";\nimport type { GithubEvent } from \"./types.js\";\n\nconst GITHUB_FORMATTING_GUIDE = `## GitHub Formatting (GitHub Flavored Markdown)\nStandard Markdown plus tables, task lists, and fenced code blocks.\nReference issues/PRs as #123 and users as @login (mentions notify people — use sparingly).`;\n\nfunction formatToolResult(result: ChatToolResult): string {\n const argsFormatted = formatToolArgs(result.args);\n const duration = (result.durationMs / 1000).toFixed(1);\n let text = `**${result.isError ? \"Error\" : \"Done\"} ${result.toolName}**`;\n if (result.label) text += `: ${result.label}`;\n text += ` (${duration}s)\\n`;\n if (argsFormatted) text += `\\`\\`\\`\\n${argsFormatted}\\n\\`\\`\\`\\n`;\n text += `**Result:**\\n\\`\\`\\`\\n${result.result}\\n\\`\\`\\``;\n return text;\n}\n\nexport function createGithubAdapters(\n event: GithubEvent,\n bot: GithubMessagingBot,\n): {\n message: ConversationMessage;\n responder: ConversationResponder;\n platform: MessagingInfo;\n} {\n let commentId: number | null = null;\n let accumulatedText = \"\";\n let updatePromise = Promise.resolve();\n\n const conversationId = event.conversationId;\n const ref = parseGithubConversationId(conversationId);\n\n const message: ConversationMessage = {\n id: event.ts,\n sessionKey:\n event.sessionKey ??\n resolveChatSessionKey({\n conversationId,\n conversationKind: event.conversationKind,\n messageId: event.ts,\n persistentTopLevel: true,\n threadTs: event.thread_ts,\n }),\n conversationKind: event.conversationKind,\n userId: event.user,\n userName: event.userName,\n text: event.text,\n attachments: event.attachments,\n threadTs: event.thread_ts,\n };\n\n const platform: MessagingInfo = {\n name: \"github\",\n formattingGuide:\n `${GITHUB_FORMATTING_GUIDE}\\n\\n` +\n `## Conversation context\\n` +\n `This conversation IS GitHub issue/PR ${ref.owner}/${ref.repo}#${ref.number}: the ` +\n `first message in the history is its title and body, and the following messages are ` +\n `its comments. When the user says \"this issue\", they mean #${ref.number}.\\n\\n` +\n `## Repository & pull requests\\n` +\n `The repository is cloned at ./repo — a snapshot from this conversation's first ` +\n `trigger. If this conversation is a pull request, its head is checked out as branch ` +\n `pr-${ref.number}. You have no git credentials, so git fetch/push fail by design.\\n` +\n `To ship code changes: branch as pi/<name> inside ./repo, commit (the git author is ` +\n `preconfigured), then call the github_pr tool to push the branch and open a pull ` +\n `request (draft: true for a draft). You cannot push the default branch or merge — ` +\n `humans review and merge every PR.`,\n channels: [],\n users: [],\n diagnostics: {\n showUsageSummary: false,\n },\n };\n\n const reportResponseError = createChatResponseErrorReporter(() => ({\n platform: \"github\",\n conversationId,\n messageId: message.id,\n sessionKey: message.sessionKey,\n responseMessageId: commentId,\n conversationKind: message.conversationKind,\n }));\n\n async function postOrUpdateResponse(displayText: string): Promise<void> {\n if (commentId !== null) {\n await bot.updateMessage(conversationId, String(commentId), displayText);\n } else {\n commentId = await bot.postComment(ref, displayText);\n }\n }\n\n async function postSplitResponse(text: string): Promise<void> {\n const [displayText, ...extraParts] = splitText(\n text,\n GITHUB_MAX_COMMENT_LENGTH,\n formatGithubContinuation,\n );\n await postOrUpdateResponse(displayText);\n for (const part of extraParts) {\n await bot.postComment(ref, part);\n }\n }\n\n async function queueGithubResponse(\n label: string,\n operation: ChatResponseErrorOperation,\n work: () => Promise<void>,\n extra: () => Record<string, unknown>,\n ): Promise<void> {\n updatePromise = updatePromise.then(async () => {\n try {\n await work();\n } catch (err) {\n log.logWarning(`GitHub ${label} error`, err instanceof Error ? err.message : String(err));\n reportResponseError(err, operation, extra());\n }\n });\n await updatePromise;\n }\n\n // No appendResponseDelta/finishResponse: GitHub gets the finished response\n // in one comment. Streaming would edit the comment on every flush — API\n // churn and \"edited\" noise for readers who refresh rather than watch typing.\n const responder: ConversationResponder = {\n respond: async (text: string) => {\n await queueGithubResponse(\n \"respond\",\n \"respond\",\n async () => {\n accumulatedText = accumulatedText ? `${accumulatedText}\\n${text}` : text;\n await postSplitResponse(accumulatedText);\n if (commentId !== null) {\n bot.logBotResponse(conversationId, text, String(commentId));\n }\n },\n () => ({\n phase: commentId ? \"update\" : \"initial_post\",\n textLength: text.length,\n accumulatedLength: accumulatedText.length,\n }),\n );\n },\n\n replaceResponse: async (text: string) => {\n await queueGithubResponse(\n \"replaceResponse\",\n \"replace_response\",\n async () => {\n accumulatedText = text;\n await postSplitResponse(accumulatedText);\n },\n () => ({\n textLength: text.length,\n hadExistingResponse: Boolean(commentId),\n }),\n );\n },\n\n respondDiagnostic: async (text: string, options?: { style?: \"muted\" | \"error\" }) => {\n await queueGithubResponse(\n \"respondDiagnostic\",\n \"respond_diagnostic\",\n async () => {\n const prefix = options?.style === \"error\" ? \"**Error:** \" : \"\";\n for (const part of splitText(\n `${prefix}${text}`,\n GITHUB_MAX_COMMENT_LENGTH,\n formatGithubContinuation,\n )) {\n await bot.postComment(ref, part);\n }\n },\n () => ({ textLength: text.length, style: options?.style }),\n );\n },\n\n respondToolResult: async (result: ChatToolResult) => {\n await responder.respondDiagnostic(formatToolResult(result));\n },\n\n // GitHub has no typing indicator; progress shows through comment edits.\n setTyping: async () => {},\n\n setWorking: async () => {},\n\n uploadFile: async (filePath: string, title?: string) => {\n // The REST API cannot attach files to comments (uploads are a browser\n // feature); leave a pointer instead of failing the run.\n const name = title ?? filePath;\n await queueGithubResponse(\n \"uploadFile\",\n \"respond_diagnostic\",\n async () => {\n await bot.postComment(\n ref,\n `*(file \\`${name}\\` was produced, but the GitHub adapter cannot attach files to comments)*`,\n );\n },\n () => ({ filePath }),\n );\n },\n\n react: async (emoji: string) => {\n await bot.addReaction(conversationId, event.ts, emoji);\n },\n\n deleteResponse: async () => {\n updatePromise = updatePromise.then(async () => {\n if (commentId !== null) {\n try {\n await bot.deleteComment(ref, commentId);\n } catch {\n // Ignore errors\n }\n commentId = null;\n }\n });\n await updatePromise;\n },\n };\n\n return { message, responder, platform };\n}\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { GithubConversationRef } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Conversation id for one issue/PR: `GH_<owner>_<repo>_<number>`.
|
|
4
|
+
*
|
|
5
|
+
* DESIGN.md originally proposed `gh:<owner>/<repo>#<number>`, but conversation
|
|
6
|
+
* ids are used verbatim as a single path segment (LAYOUT.md § Casing) and the
|
|
7
|
+
* conversation dir is bind-mounted with docker's `-v source:target` syntax in
|
|
8
|
+
* image mode — so the id can contain neither `/` nor `:`. `_` is the
|
|
9
|
+
* separator because it is the only inert character that also parses back
|
|
10
|
+
* unambiguously under GitHub's name grammar: owners allow `-` (so `-` would
|
|
11
|
+
* make the owner/repo boundary ambiguous) but never `_`, repos may contain
|
|
12
|
+
* `_` but the trailing number is pure digits — so the first `_` and the last
|
|
13
|
+
* `_` before the digits are always the real boundaries.
|
|
14
|
+
*
|
|
15
|
+
* Owner and repo are lowercased: GitHub names are case-insensitive (and this
|
|
16
|
+
* id has two spelling sources — the GITHUB_REPOS env var and API payloads),
|
|
17
|
+
* so per LAYOUT.md § Casing this is a mikan-derived slug, not a verbatim
|
|
18
|
+
* platform id, and derived slugs are lowercased to keep one issue from
|
|
19
|
+
* mapping to two conversation dirs on case-sensitive filesystems.
|
|
20
|
+
*/
|
|
21
|
+
export declare function buildGithubConversationId(ref: GithubConversationRef): string;
|
|
22
|
+
export declare function parseGithubConversationId(conversationId: string): GithubConversationRef;
|
|
23
|
+
/** Message ts used for the issue/PR body itself (comments use their comment id). */
|
|
24
|
+
export declare const GITHUB_ISSUE_BODY_TS = "issue";
|
|
25
|
+
//# sourceMappingURL=ids.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../../../src/adapters/github/ids.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAExD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,qBAAqB,GAAG,MAAM,CAE5E;AAID,wBAAgB,yBAAyB,CAAC,cAAc,EAAE,MAAM,GAAG,qBAAqB,CAYvF;AAED,oFAAoF;AACpF,eAAO,MAAM,oBAAoB,UAAU,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conversation id for one issue/PR: `GH_<owner>_<repo>_<number>`.
|
|
3
|
+
*
|
|
4
|
+
* DESIGN.md originally proposed `gh:<owner>/<repo>#<number>`, but conversation
|
|
5
|
+
* ids are used verbatim as a single path segment (LAYOUT.md § Casing) and the
|
|
6
|
+
* conversation dir is bind-mounted with docker's `-v source:target` syntax in
|
|
7
|
+
* image mode — so the id can contain neither `/` nor `:`. `_` is the
|
|
8
|
+
* separator because it is the only inert character that also parses back
|
|
9
|
+
* unambiguously under GitHub's name grammar: owners allow `-` (so `-` would
|
|
10
|
+
* make the owner/repo boundary ambiguous) but never `_`, repos may contain
|
|
11
|
+
* `_` but the trailing number is pure digits — so the first `_` and the last
|
|
12
|
+
* `_` before the digits are always the real boundaries.
|
|
13
|
+
*
|
|
14
|
+
* Owner and repo are lowercased: GitHub names are case-insensitive (and this
|
|
15
|
+
* id has two spelling sources — the GITHUB_REPOS env var and API payloads),
|
|
16
|
+
* so per LAYOUT.md § Casing this is a mikan-derived slug, not a verbatim
|
|
17
|
+
* platform id, and derived slugs are lowercased to keep one issue from
|
|
18
|
+
* mapping to two conversation dirs on case-sensitive filesystems.
|
|
19
|
+
*/
|
|
20
|
+
export function buildGithubConversationId(ref) {
|
|
21
|
+
return `GH_${ref.owner.toLowerCase()}_${ref.repo.toLowerCase()}_${ref.number}`;
|
|
22
|
+
}
|
|
23
|
+
const CONVERSATION_ID_PATTERN = /^GH_([A-Za-z0-9-]+)_(.+)_(\d+)$/;
|
|
24
|
+
export function parseGithubConversationId(conversationId) {
|
|
25
|
+
// The greedy repo group splits at the last `_` followed by digits-to-end,
|
|
26
|
+
// which is always the number boundary (repos may contain `_` themselves).
|
|
27
|
+
const match = CONVERSATION_ID_PATTERN.exec(conversationId);
|
|
28
|
+
if (!match) {
|
|
29
|
+
throw new Error(`Not a GitHub conversation id: ${conversationId}`);
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
owner: match[1].toLowerCase(),
|
|
33
|
+
repo: match[2].toLowerCase(),
|
|
34
|
+
number: Number(match[3]),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** Message ts used for the issue/PR body itself (comments use their comment id). */
|
|
38
|
+
export const GITHUB_ISSUE_BODY_TS = "issue";
|
|
39
|
+
//# sourceMappingURL=ids.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ids.js","sourceRoot":"","sources":["../../../src/adapters/github/ids.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,yBAAyB,CAAC,GAA0B;IAClE,OAAO,MAAM,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;AACjF,CAAC;AAED,MAAM,uBAAuB,GAAG,iCAAiC,CAAC;AAElE,MAAM,UAAU,yBAAyB,CAAC,cAAsB;IAC9D,0EAA0E;IAC1E,0EAA0E;IAC1E,MAAM,KAAK,GAAG,uBAAuB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC3D,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,iCAAiC,cAAc,EAAE,CAAC,CAAC;IACrE,CAAC;IACD,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;QAC7B,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE;QAC5B,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;KACzB,CAAC;AACJ,CAAC;AAED,oFAAoF;AACpF,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAAO,CAAC","sourcesContent":["import type { GithubConversationRef } from \"./types.js\";\n\n/**\n * Conversation id for one issue/PR: `GH_<owner>_<repo>_<number>`.\n *\n * DESIGN.md originally proposed `gh:<owner>/<repo>#<number>`, but conversation\n * ids are used verbatim as a single path segment (LAYOUT.md § Casing) and the\n * conversation dir is bind-mounted with docker's `-v source:target` syntax in\n * image mode — so the id can contain neither `/` nor `:`. `_` is the\n * separator because it is the only inert character that also parses back\n * unambiguously under GitHub's name grammar: owners allow `-` (so `-` would\n * make the owner/repo boundary ambiguous) but never `_`, repos may contain\n * `_` but the trailing number is pure digits — so the first `_` and the last\n * `_` before the digits are always the real boundaries.\n *\n * Owner and repo are lowercased: GitHub names are case-insensitive (and this\n * id has two spelling sources — the GITHUB_REPOS env var and API payloads),\n * so per LAYOUT.md § Casing this is a mikan-derived slug, not a verbatim\n * platform id, and derived slugs are lowercased to keep one issue from\n * mapping to two conversation dirs on case-sensitive filesystems.\n */\nexport function buildGithubConversationId(ref: GithubConversationRef): string {\n return `GH_${ref.owner.toLowerCase()}_${ref.repo.toLowerCase()}_${ref.number}`;\n}\n\nconst CONVERSATION_ID_PATTERN = /^GH_([A-Za-z0-9-]+)_(.+)_(\\d+)$/;\n\nexport function parseGithubConversationId(conversationId: string): GithubConversationRef {\n // The greedy repo group splits at the last `_` followed by digits-to-end,\n // which is always the number boundary (repos may contain `_` themselves).\n const match = CONVERSATION_ID_PATTERN.exec(conversationId);\n if (!match) {\n throw new Error(`Not a GitHub conversation id: ${conversationId}`);\n }\n return {\n owner: match[1].toLowerCase(),\n repo: match[2].toLowerCase(),\n number: Number(match[3]),\n };\n}\n\n/** Message ts used for the issue/PR body itself (comments use their comment id). */\nexport const GITHUB_ISSUE_BODY_TS = \"issue\";\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CloneRepoOptions, PushBranchOptions } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Branches the bot may push: `pi/<name>`. Everything else — including the
|
|
4
|
+
* repo's default branch by construction — is refused, so a driven agent can
|
|
5
|
+
* only ever produce reviewable branches, never touch mainline directly.
|
|
6
|
+
*/
|
|
7
|
+
export declare const GITHUB_PUSH_BRANCH_PATTERN: RegExp;
|
|
8
|
+
/**
|
|
9
|
+
* Shallow-clone a repo into a conversation dir and preconfigure the bot's
|
|
10
|
+
* commit identity. For PR conversations, additionally fetch the PR head and
|
|
11
|
+
* check it out as `pr-<number>` so the agent starts on the code under review.
|
|
12
|
+
*/
|
|
13
|
+
export declare function cloneRepo(options: CloneRepoOptions): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Push one local branch to origin. Non-force by construction (plain refspec),
|
|
16
|
+
* and only `pi/*` branches are accepted.
|
|
17
|
+
*/
|
|
18
|
+
export declare function pushBranch(options: PushBranchOptions): Promise<void>;
|
|
19
|
+
//# sourceMappingURL=repo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repo.d.ts","sourceRoot":"","sources":["../../../src/adapters/github/repo.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAMtE;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,QAAwC,CAAC;AAoBhF;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAWxE;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAa1E"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { execFile } from "child_process";
|
|
2
|
+
import { promisify } from "util";
|
|
3
|
+
const execFileAsync = promisify(execFile);
|
|
4
|
+
const GIT_TIMEOUT_MS = 120_000;
|
|
5
|
+
/**
|
|
6
|
+
* Branches the bot may push: `pi/<name>`. Everything else — including the
|
|
7
|
+
* repo's default branch by construction — is refused, so a driven agent can
|
|
8
|
+
* only ever produce reviewable branches, never touch mainline directly.
|
|
9
|
+
*/
|
|
10
|
+
export const GITHUB_PUSH_BRANCH_PATTERN = /^pi\/[A-Za-z0-9._][A-Za-z0-9._/-]*$/;
|
|
11
|
+
/**
|
|
12
|
+
* Pass the ephemeral token as a per-invocation header, never in the remote
|
|
13
|
+
* URL: nothing credential-shaped may end up in `.git/config`, which lives in
|
|
14
|
+
* the conversation dir and is bind-mounted into the sandbox.
|
|
15
|
+
*/
|
|
16
|
+
function gitAuthArgs(token) {
|
|
17
|
+
const basic = Buffer.from(`x-access-token:${token}`).toString("base64");
|
|
18
|
+
return ["-c", `http.extraheader=Authorization: basic ${basic}`];
|
|
19
|
+
}
|
|
20
|
+
async function git(args, token) {
|
|
21
|
+
const { stdout } = await execFileAsync("git", [...(token ? gitAuthArgs(token) : []), ...args], {
|
|
22
|
+
timeout: GIT_TIMEOUT_MS,
|
|
23
|
+
env: { ...process.env, GIT_TERMINAL_PROMPT: "0" },
|
|
24
|
+
});
|
|
25
|
+
return stdout;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Shallow-clone a repo into a conversation dir and preconfigure the bot's
|
|
29
|
+
* commit identity. For PR conversations, additionally fetch the PR head and
|
|
30
|
+
* check it out as `pr-<number>` so the agent starts on the code under review.
|
|
31
|
+
*/
|
|
32
|
+
export async function cloneRepo(options) {
|
|
33
|
+
await git(["clone", "--depth", "50", options.url, options.dir], options.token);
|
|
34
|
+
await git(["-C", options.dir, "config", "user.name", options.botLogin]);
|
|
35
|
+
await git(["-C", options.dir, "config", "user.email", options.botEmail]);
|
|
36
|
+
if (options.prNumber !== undefined) {
|
|
37
|
+
await git(["-C", options.dir, "fetch", "--depth", "50", "origin", `pull/${options.prNumber}/head`], options.token);
|
|
38
|
+
await git(["-C", options.dir, "checkout", "-B", `pr-${options.prNumber}`, "FETCH_HEAD"]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Push one local branch to origin. Non-force by construction (plain refspec),
|
|
43
|
+
* and only `pi/*` branches are accepted.
|
|
44
|
+
*/
|
|
45
|
+
export async function pushBranch(options) {
|
|
46
|
+
const { dir, branch, token } = options;
|
|
47
|
+
if (!GITHUB_PUSH_BRANCH_PATTERN.test(branch)) {
|
|
48
|
+
throw new Error(`Refusing to push branch '${branch}': only branches matching pi/<name> may be pushed.`);
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
await git(["-C", dir, "rev-parse", "--verify", "--quiet", `refs/heads/${branch}`]);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
throw new Error(`Branch '${branch}' does not exist in the conversation's ./repo clone.`);
|
|
55
|
+
}
|
|
56
|
+
await git(["-C", dir, "push", "origin", `refs/heads/${branch}:refs/heads/${branch}`], token);
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=repo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repo.js","sourceRoot":"","sources":["../../../src/adapters/github/repo.ts"],"names":[],"mappings":"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","sourcesContent":["import { execFile } from \"child_process\";\nimport { promisify } from \"util\";\nimport type { CloneRepoOptions, PushBranchOptions } from \"./types.js\";\n\nconst execFileAsync = promisify(execFile);\n\nconst GIT_TIMEOUT_MS = 120_000;\n\n/**\n * Branches the bot may push: `pi/<name>`. Everything else — including the\n * repo's default branch by construction — is refused, so a driven agent can\n * only ever produce reviewable branches, never touch mainline directly.\n */\nexport const GITHUB_PUSH_BRANCH_PATTERN = /^pi\\/[A-Za-z0-9._][A-Za-z0-9._/-]*$/;\n\n/**\n * Pass the ephemeral token as a per-invocation header, never in the remote\n * URL: nothing credential-shaped may end up in `.git/config`, which lives in\n * the conversation dir and is bind-mounted into the sandbox.\n */\nfunction gitAuthArgs(token: string): string[] {\n const basic = Buffer.from(`x-access-token:${token}`).toString(\"base64\");\n return [\"-c\", `http.extraheader=Authorization: basic ${basic}`];\n}\n\nasync function git(args: string[], token?: string): Promise<string> {\n const { stdout } = await execFileAsync(\"git\", [...(token ? gitAuthArgs(token) : []), ...args], {\n timeout: GIT_TIMEOUT_MS,\n env: { ...process.env, GIT_TERMINAL_PROMPT: \"0\" },\n });\n return stdout;\n}\n\n/**\n * Shallow-clone a repo into a conversation dir and preconfigure the bot's\n * commit identity. For PR conversations, additionally fetch the PR head and\n * check it out as `pr-<number>` so the agent starts on the code under review.\n */\nexport async function cloneRepo(options: CloneRepoOptions): Promise<void> {\n await git([\"clone\", \"--depth\", \"50\", options.url, options.dir], options.token);\n await git([\"-C\", options.dir, \"config\", \"user.name\", options.botLogin]);\n await git([\"-C\", options.dir, \"config\", \"user.email\", options.botEmail]);\n if (options.prNumber !== undefined) {\n await git(\n [\"-C\", options.dir, \"fetch\", \"--depth\", \"50\", \"origin\", `pull/${options.prNumber}/head`],\n options.token,\n );\n await git([\"-C\", options.dir, \"checkout\", \"-B\", `pr-${options.prNumber}`, \"FETCH_HEAD\"]);\n }\n}\n\n/**\n * Push one local branch to origin. Non-force by construction (plain refspec),\n * and only `pi/*` branches are accepted.\n */\nexport async function pushBranch(options: PushBranchOptions): Promise<void> {\n const { dir, branch, token } = options;\n if (!GITHUB_PUSH_BRANCH_PATTERN.test(branch)) {\n throw new Error(\n `Refusing to push branch '${branch}': only branches matching pi/<name> may be pushed.`,\n );\n }\n try {\n await git([\"-C\", dir, \"rev-parse\", \"--verify\", \"--quiet\", `refs/heads/${branch}`]);\n } catch {\n throw new Error(`Branch '${branch}' does not exist in the conversation's ./repo clone.`);\n }\n await git([\"-C\", dir, \"push\", \"origin\", `refs/heads/${branch}:refs/heads/${branch}`], token);\n}\n"]}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { ConversationEvent } from "../../adapter.js";
|
|
2
|
+
export interface GithubEvent extends ConversationEvent {
|
|
3
|
+
type: "message" | "issue";
|
|
4
|
+
userName?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface GithubBotConfig {
|
|
7
|
+
appId: string;
|
|
8
|
+
/** PEM-encoded GitHub App private key. */
|
|
9
|
+
privateKey: string;
|
|
10
|
+
installationId: string;
|
|
11
|
+
/** `owner/repo` entries to watch; empty = all installation repositories. */
|
|
12
|
+
repos: string[];
|
|
13
|
+
pollIntervalMs: number;
|
|
14
|
+
workingDir: string;
|
|
15
|
+
/**
|
|
16
|
+
* Where the poll watermark state (baseline + seen ids) is persisted. Lives
|
|
17
|
+
* under the host-only state dir: the workspace dir can be mounted into
|
|
18
|
+
* sandboxes, and sandboxed code must not be able to clear dedup state and
|
|
19
|
+
* re-trigger runs.
|
|
20
|
+
*/
|
|
21
|
+
syncStatePath: string;
|
|
22
|
+
}
|
|
23
|
+
/** Persisted per-repo poll watermark (DESIGN.md § Event source). */
|
|
24
|
+
interface GithubRepoSyncState {
|
|
25
|
+
/** Comments/issues created before this ISO instant never trigger. */
|
|
26
|
+
baseline: string;
|
|
27
|
+
/** Newest updated_at seen; polls fetch from (cursor - overlap). */
|
|
28
|
+
cursor: string;
|
|
29
|
+
seenComments: number[];
|
|
30
|
+
seenIssues: number[];
|
|
31
|
+
}
|
|
32
|
+
export interface GithubSyncState {
|
|
33
|
+
repos: Record<string, GithubRepoSyncState>;
|
|
34
|
+
}
|
|
35
|
+
export interface GithubRepoRef {
|
|
36
|
+
owner: string;
|
|
37
|
+
repo: string;
|
|
38
|
+
}
|
|
39
|
+
export interface GithubConversationRef extends GithubRepoRef {
|
|
40
|
+
number: number;
|
|
41
|
+
}
|
|
42
|
+
interface GithubUser {
|
|
43
|
+
login: string;
|
|
44
|
+
type: string;
|
|
45
|
+
}
|
|
46
|
+
export interface GithubIssue {
|
|
47
|
+
id: number;
|
|
48
|
+
number: number;
|
|
49
|
+
title: string;
|
|
50
|
+
body: string | null;
|
|
51
|
+
user: GithubUser;
|
|
52
|
+
created_at: string;
|
|
53
|
+
updated_at: string;
|
|
54
|
+
pull_request?: object;
|
|
55
|
+
}
|
|
56
|
+
export interface GithubIssueComment {
|
|
57
|
+
id: number;
|
|
58
|
+
body: string;
|
|
59
|
+
user: GithubUser;
|
|
60
|
+
created_at: string;
|
|
61
|
+
updated_at: string;
|
|
62
|
+
/** API URL of the parent issue, e.g. …/repos/o/r/issues/42 */
|
|
63
|
+
issue_url: string;
|
|
64
|
+
}
|
|
65
|
+
export interface GithubRepository {
|
|
66
|
+
name: string;
|
|
67
|
+
owner: GithubUser;
|
|
68
|
+
}
|
|
69
|
+
export interface GithubRepositoryDetails {
|
|
70
|
+
default_branch: string;
|
|
71
|
+
}
|
|
72
|
+
export interface GithubCollaboratorPermission {
|
|
73
|
+
/** Legacy field: admin | write | read | none (maintain→write, triage→read). */
|
|
74
|
+
permission: string;
|
|
75
|
+
/** Granular assigned role (admin/maintain/write/triage/read or a custom role). */
|
|
76
|
+
role_name?: string;
|
|
77
|
+
}
|
|
78
|
+
export interface GithubPullRequest {
|
|
79
|
+
number: number;
|
|
80
|
+
html_url: string;
|
|
81
|
+
}
|
|
82
|
+
/** Permission subset requestable on a scoped installation token. */
|
|
83
|
+
export type GithubTokenPermissions = Partial<Record<"contents" | "pull_requests" | "issues", "read" | "write">>;
|
|
84
|
+
export type GithubReactionContent = "+1" | "-1" | "laugh" | "confused" | "heart" | "hooray" | "rocket" | "eyes";
|
|
85
|
+
export interface CloneRepoOptions {
|
|
86
|
+
/** HTTPS remote, e.g. https://github.com/owner/repo.git (no credentials). */
|
|
87
|
+
url: string;
|
|
88
|
+
/** Destination directory (the conversation dir's `repo/`). */
|
|
89
|
+
dir: string;
|
|
90
|
+
/** Ephemeral scoped installation token; used per-invocation, never stored. */
|
|
91
|
+
token: string;
|
|
92
|
+
botLogin: string;
|
|
93
|
+
botEmail: string;
|
|
94
|
+
/** When the conversation is a PR: fetch and checkout its head as pr-<n>. */
|
|
95
|
+
prNumber?: number;
|
|
96
|
+
}
|
|
97
|
+
export interface PushBranchOptions {
|
|
98
|
+
dir: string;
|
|
99
|
+
branch: string;
|
|
100
|
+
token: string;
|
|
101
|
+
}
|
|
102
|
+
export interface GithubClientOptions {
|
|
103
|
+
appId: string;
|
|
104
|
+
privateKey: string;
|
|
105
|
+
installationId: string;
|
|
106
|
+
/** Override the API root for tests; defaults to https://api.github.com */
|
|
107
|
+
baseUrl?: string;
|
|
108
|
+
fetchImpl?: typeof fetch;
|
|
109
|
+
}
|
|
110
|
+
export {};
|
|
111
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/adapters/github/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/adapters/github/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { ConversationEvent } from \"../../adapter.js\";\n\nexport interface GithubEvent extends ConversationEvent {\n type: \"message\" | \"issue\";\n userName?: string;\n}\n\nexport interface GithubBotConfig {\n appId: string;\n /** PEM-encoded GitHub App private key. */\n privateKey: string;\n installationId: string;\n /** `owner/repo` entries to watch; empty = all installation repositories. */\n repos: string[];\n pollIntervalMs: number;\n workingDir: string;\n /**\n * Where the poll watermark state (baseline + seen ids) is persisted. Lives\n * under the host-only state dir: the workspace dir can be mounted into\n * sandboxes, and sandboxed code must not be able to clear dedup state and\n * re-trigger runs.\n */\n syncStatePath: string;\n}\n\n/** Persisted per-repo poll watermark (DESIGN.md § Event source). */\ninterface GithubRepoSyncState {\n /** Comments/issues created before this ISO instant never trigger. */\n baseline: string;\n /** Newest updated_at seen; polls fetch from (cursor - overlap). */\n cursor: string;\n seenComments: number[];\n seenIssues: number[];\n}\n\nexport interface GithubSyncState {\n repos: Record<string, GithubRepoSyncState>;\n}\n\nexport interface GithubRepoRef {\n owner: string;\n repo: string;\n}\n\nexport interface GithubConversationRef extends GithubRepoRef {\n number: number;\n}\n\n// ── GitHub REST payload shapes (only the fields mikan reads) ─────────────────\n\ninterface GithubUser {\n login: string;\n type: string;\n}\n\nexport interface GithubIssue {\n id: number;\n number: number;\n title: string;\n body: string | null;\n user: GithubUser;\n created_at: string;\n updated_at: string;\n pull_request?: object;\n}\n\nexport interface GithubIssueComment {\n id: number;\n body: string;\n user: GithubUser;\n created_at: string;\n updated_at: string;\n /** API URL of the parent issue, e.g. …/repos/o/r/issues/42 */\n issue_url: string;\n}\n\nexport interface GithubRepository {\n name: string;\n owner: GithubUser;\n}\n\nexport interface GithubRepositoryDetails {\n default_branch: string;\n}\n\nexport interface GithubCollaboratorPermission {\n /** Legacy field: admin | write | read | none (maintain→write, triage→read). */\n permission: string;\n /** Granular assigned role (admin/maintain/write/triage/read or a custom role). */\n role_name?: string;\n}\n\nexport interface GithubPullRequest {\n number: number;\n html_url: string;\n}\n\n/** Permission subset requestable on a scoped installation token. */\nexport type GithubTokenPermissions = Partial<\n Record<\"contents\" | \"pull_requests\" | \"issues\", \"read\" | \"write\">\n>;\n\nexport type GithubReactionContent =\n | \"+1\"\n | \"-1\"\n | \"laugh\"\n | \"confused\"\n | \"heart\"\n | \"hooray\"\n | \"rocket\"\n | \"eyes\";\n\nexport interface CloneRepoOptions {\n /** HTTPS remote, e.g. https://github.com/owner/repo.git (no credentials). */\n url: string;\n /** Destination directory (the conversation dir's `repo/`). */\n dir: string;\n /** Ephemeral scoped installation token; used per-invocation, never stored. */\n token: string;\n botLogin: string;\n botEmail: string;\n /** When the conversation is a PR: fetch and checkout its head as pr-<n>. */\n prNumber?: number;\n}\n\nexport interface PushBranchOptions {\n dir: string;\n branch: string;\n token: string;\n}\n\nexport interface GithubClientOptions {\n appId: string;\n privateKey: string;\n installationId: string;\n /** Override the API root for tests; defaults to https://api.github.com */\n baseUrl?: string;\n fetchImpl?: typeof fetch;\n}\n"]}
|
package/dist/agent.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ImageContent } from "@earendil-works/pi-ai";
|
|
2
2
|
import type { ConversationMessage } from "./adapter.js";
|
|
3
|
-
import type { PlatformNotifier, PlatformReactor } from "./types.js";
|
|
3
|
+
import type { PlatformNotifier, PlatformPrCreator, PlatformReactor } from "./types.js";
|
|
4
4
|
import type { SessionViewTokenStoreLike } from "./commands/types.js";
|
|
5
5
|
import type { DockerContainerManager } from "./provisioner.js";
|
|
6
6
|
import { type RuntimePathContext, type SandboxConfig } from "./sandbox/index.js";
|
|
@@ -33,7 +33,7 @@ export declare function appendTriggerAttribution(text: string, triggerAttributio
|
|
|
33
33
|
export declare function createRunner(sandboxConfig: SandboxConfig, sessionKey: string, conversationId: string, conversationDir: string, workspaceDir: string, sessionScope: ResolvedSessionScope, vaultManager?: VaultManager, provisioner?: DockerContainerManager, sessionView?: {
|
|
34
34
|
tokenStore: SessionViewTokenStoreLike;
|
|
35
35
|
portalBaseUrl?: string;
|
|
36
|
-
}, platformNotifier?: PlatformNotifier, platformReactor?: PlatformReactor): Promise<PiAgentWrapper>;
|
|
36
|
+
}, platformNotifier?: PlatformNotifier, platformReactor?: PlatformReactor, platformPrCreator?: PlatformPrCreator): Promise<PiAgentWrapper>;
|
|
37
37
|
export declare function translateRuntimePathToHost(runtimePath: string, pathContext: RuntimePathContext): string;
|
|
38
38
|
export declare function translateAttachPathToHost(filePath: string, pathContext: RuntimePathContext): string;
|
|
39
39
|
//# sourceMappingURL=agent.d.ts.map
|
package/dist/agent.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,KAAK,YAAY,EAAc,MAAM,uBAAuB,CAAC;AAkBhF,OAAO,KAAK,EACV,mBAAmB,EAKpB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,KAAK,YAAY,EAAc,MAAM,uBAAuB,CAAC;AAkBhF,OAAO,KAAK,EACV,mBAAmB,EAKpB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAKV,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EAChB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAMrE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAGL,KAAK,kBAAkB,EACvB,KAAK,aAAa,EACnB,MAAM,oBAAoB,CAAC;AAO5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,EAGL,KAAK,oBAAoB,EAE1B,MAAM,qBAAqB,CAAC;AAQ7B,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAyIjD,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,IAAI,CAAC,mBAAmB,EAAE,IAAI,GAAG,MAAM,GAAG,UAAU,CAAC,GAC7D,MAAM,GAAG,SAAS,CAOpB;AA6KD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,cAAc,EAAE,OAAO,EACvB,kBAAkB,EAAE,MAAM,GAAG,SAAS,EACtC,YAAY,EAAE,MAAM,GACnB,MAAM,CAkBR;AAED,wBAAgB,+BAA+B,CAC7C,aAAa,EAAE,aAAa,EAC5B,iBAAiB,EAAE,MAAM,GACxB,kBAAkB,CAMpB;AAiVD,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,mBAAmB,EAC5B,aAAa,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,kBAAkB,GAC/B;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,YAAY,EAAE,CAAC;CAClC,CAaA;AA+BD,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,EACZ,kBAAkB,EAAE,MAAM,GAAG,SAAS,EACtC,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,CAYR;AAytBD;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,aAAa,EAAE,aAAa,EAC5B,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,MAAM,EACvB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,oBAAoB,EAClC,YAAY,CAAC,EAAE,YAAY,EAC3B,WAAW,CAAC,EAAE,sBAAsB,EACpC,WAAW,CAAC,EAAE;IACZ,UAAU,EAAE,yBAAyB,CAAC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,EACD,gBAAgB,CAAC,EAAE,gBAAgB,EACnC,eAAe,CAAC,EAAE,eAAe,EACjC,iBAAiB,CAAC,EAAE,iBAAiB,GACpC,OAAO,CAAC,cAAc,CAAC,CAgOzB;AAED,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,kBAAkB,GAC9B,MAAM,CAER;AAED,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,kBAAkB,GAC9B,MAAM,CAKR"}
|
package/dist/agent.js
CHANGED
|
@@ -794,6 +794,12 @@ async function prepareRunContext(params) {
|
|
|
794
794
|
// (interactive turns on platforms with reaction support); otherwise unset
|
|
795
795
|
// so the tool reports it is unavailable rather than silently no-op'ing.
|
|
796
796
|
setReactFunction(responder.react ? async (emoji) => responder.react(emoji) : null);
|
|
797
|
+
// github_pr is available only in GitHub conversations with a wired creator;
|
|
798
|
+
// everywhere else the tool reports itself unavailable.
|
|
799
|
+
const { platformPrCreator, setGithubPrFunction } = params;
|
|
800
|
+
setGithubPrFunction(platform.name === "github" && platformPrCreator
|
|
801
|
+
? (request) => platformPrCreator(conversationId, request)
|
|
802
|
+
: null);
|
|
797
803
|
resetRunState(runState, responder, sessionConversation, message.userName, sessionUuid, triggerAttribution);
|
|
798
804
|
const runQueue = createRunQueue(responder, runState);
|
|
799
805
|
runState.queue = runQueue.queue;
|
|
@@ -1109,13 +1115,13 @@ function extractToolResultText(result) {
|
|
|
1109
1115
|
* Runner caching is handled by the caller (channelStates in main.ts).
|
|
1110
1116
|
* This is a stateless factory function.
|
|
1111
1117
|
*/
|
|
1112
|
-
export async function createRunner(sandboxConfig, sessionKey, conversationId, conversationDir, workspaceDir, sessionScope, vaultManager, provisioner, sessionView, platformNotifier, platformReactor) {
|
|
1118
|
+
export async function createRunner(sandboxConfig, sessionKey, conversationId, conversationDir, workspaceDir, sessionScope, vaultManager, provisioner, sessionView, platformNotifier, platformReactor, platformPrCreator) {
|
|
1113
1119
|
const agentConfig = resolveConversationSettings(conversationDir);
|
|
1114
1120
|
const workspaceBase = join(conversationDir, "..");
|
|
1115
1121
|
const { executionResolver, executor, getPathContext, resolveExecutorForRun } = createRunnerExecutionContext(sandboxConfig, vaultManager, provisioner, workspaceDir, workspaceBase);
|
|
1116
1122
|
let pathContext = getUnresolvedSandboxPathContext(sandboxConfig, workspaceBase);
|
|
1117
1123
|
// Create tools (per-runner, with per-runner upload function setter)
|
|
1118
|
-
const { tools, setUploadFunction, setReactFunction, setEventContext, setSandboxContext } = createMikanTools(executor, workspaceDir, { sandbox: sandboxConfig, provisioner });
|
|
1124
|
+
const { tools, setUploadFunction, setReactFunction, setGithubPrFunction, setEventContext, setSandboxContext, } = createMikanTools(executor, workspaceDir, { sandbox: sandboxConfig, provisioner });
|
|
1119
1125
|
const modelRegistry = MikanModels.create();
|
|
1120
1126
|
if (modelRegistry.getError()) {
|
|
1121
1127
|
log.logWarning("models.json load error", modelRegistry.getError());
|
|
@@ -1187,6 +1193,8 @@ export async function createRunner(sandboxConfig, sessionKey, conversationId, co
|
|
|
1187
1193
|
setSandboxContext,
|
|
1188
1194
|
setUploadFunction,
|
|
1189
1195
|
setReactFunction,
|
|
1196
|
+
setGithubPrFunction,
|
|
1197
|
+
platformPrCreator,
|
|
1190
1198
|
pathContext,
|
|
1191
1199
|
});
|
|
1192
1200
|
pathContext = prepared.pathContext;
|