@ubiquity-os/plugin-sdk 3.6.2 → 3.7.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/dist/configuration.d.mts +20 -11
- package/dist/configuration.d.ts +20 -11
- package/dist/configuration.js +241 -51
- package/dist/configuration.mjs +241 -51
- package/dist/{context-BbEmsEct.d.ts → context-BE4WjJZf.d.ts} +1 -0
- package/dist/{context-sqbr2o6i.d.mts → context-Ckj1HMjz.d.mts} +1 -0
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +306 -157
- package/dist/index.mjs +306 -157
- package/dist/llm.d.mts +2 -2
- package/dist/llm.d.ts +2 -2
- package/dist/llm.js +142 -43
- package/dist/llm.mjs +142 -43
- package/dist/signature.js +2 -2
- package/dist/signature.mjs +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -41,7 +41,6 @@ module.exports = __toCommonJS(src_exports);
|
|
|
41
41
|
|
|
42
42
|
// src/actions.ts
|
|
43
43
|
var core = __toESM(require("@actions/core"));
|
|
44
|
-
var github2 = __toESM(require("@actions/github"));
|
|
45
44
|
var import_value3 = require("@sinclair/typebox/value");
|
|
46
45
|
|
|
47
46
|
// ../../node_modules/@ubiquity-os/ubiquity-os-logger/dist/index.js
|
|
@@ -379,8 +378,56 @@ var Logs = class _Logs {
|
|
|
379
378
|
// src/actions.ts
|
|
380
379
|
var import_dotenv = require("dotenv");
|
|
381
380
|
|
|
382
|
-
// src/
|
|
383
|
-
|
|
381
|
+
// src/error.ts
|
|
382
|
+
function getErrorStatus(err) {
|
|
383
|
+
if (!err || typeof err !== "object") return null;
|
|
384
|
+
const candidate = err;
|
|
385
|
+
const directStatus = candidate.status ?? candidate.response?.status;
|
|
386
|
+
if (typeof directStatus === "number" && Number.isFinite(directStatus)) return directStatus;
|
|
387
|
+
if (typeof directStatus === "string" && directStatus.trim()) {
|
|
388
|
+
const parsed = Number.parseInt(directStatus, 10);
|
|
389
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
390
|
+
}
|
|
391
|
+
if (err instanceof Error) {
|
|
392
|
+
const match = /LLM API error:\s*(\d{3})/i.exec(err.message);
|
|
393
|
+
if (match) {
|
|
394
|
+
const parsed = Number.parseInt(match[1], 10);
|
|
395
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
function logByStatus(context, message, metadata) {
|
|
401
|
+
const status = getErrorStatus(metadata.err);
|
|
402
|
+
const payload = { ...metadata, ...status ? { status } : {} };
|
|
403
|
+
if (status && status >= 500) return context.logger.error(message, payload);
|
|
404
|
+
if (status && status >= 400) return context.logger.warn(message, payload);
|
|
405
|
+
if (status && status >= 300) return context.logger.debug(message, payload);
|
|
406
|
+
if (status && status >= 200) return context.logger.ok(message, payload);
|
|
407
|
+
if (status && status >= 100) return context.logger.info(message, payload);
|
|
408
|
+
return context.logger.error(message, payload);
|
|
409
|
+
}
|
|
410
|
+
function transformError(context, error) {
|
|
411
|
+
if (error instanceof LogReturn) {
|
|
412
|
+
return error;
|
|
413
|
+
}
|
|
414
|
+
if (error instanceof AggregateError) {
|
|
415
|
+
const message = error.errors.map((err) => {
|
|
416
|
+
if (err instanceof LogReturn) {
|
|
417
|
+
return err.logMessage.raw;
|
|
418
|
+
}
|
|
419
|
+
if (err instanceof Error) {
|
|
420
|
+
return err.message;
|
|
421
|
+
}
|
|
422
|
+
return String(err);
|
|
423
|
+
}).join("\n\n");
|
|
424
|
+
return logByStatus(context, message, { err: error });
|
|
425
|
+
}
|
|
426
|
+
if (error instanceof Error) {
|
|
427
|
+
return logByStatus(context, error.message, { err: error });
|
|
428
|
+
}
|
|
429
|
+
return logByStatus(context, String(error), { err: error });
|
|
430
|
+
}
|
|
384
431
|
|
|
385
432
|
// ../../node_modules/hono/dist/helper/adapter/index.js
|
|
386
433
|
var env = (c, runtime) => {
|
|
@@ -432,6 +479,21 @@ var checkUserAgentEquals = (platform) => {
|
|
|
432
479
|
return userAgent.startsWith(platform);
|
|
433
480
|
};
|
|
434
481
|
|
|
482
|
+
// src/helpers/github-context.ts
|
|
483
|
+
var github = __toESM(require("@actions/github"));
|
|
484
|
+
function getGithubContext() {
|
|
485
|
+
const override = globalThis.__UOS_GITHUB_CONTEXT__;
|
|
486
|
+
if (override) {
|
|
487
|
+
return override;
|
|
488
|
+
}
|
|
489
|
+
const module2 = github;
|
|
490
|
+
const context = module2.context ?? module2.default?.context;
|
|
491
|
+
if (!context) {
|
|
492
|
+
throw new Error("GitHub context is unavailable.");
|
|
493
|
+
}
|
|
494
|
+
return context;
|
|
495
|
+
}
|
|
496
|
+
|
|
435
497
|
// src/helpers/runtime-info.ts
|
|
436
498
|
var PluginRuntimeInfo = class _PluginRuntimeInfo {
|
|
437
499
|
static _instance = null;
|
|
@@ -480,10 +542,11 @@ var CfRuntimeInfo = class extends PluginRuntimeInfo {
|
|
|
480
542
|
};
|
|
481
543
|
var NodeRuntimeInfo = class extends PluginRuntimeInfo {
|
|
482
544
|
get version() {
|
|
483
|
-
return
|
|
545
|
+
return getGithubContext().sha;
|
|
484
546
|
}
|
|
485
547
|
get runUrl() {
|
|
486
|
-
|
|
548
|
+
const context = getGithubContext();
|
|
549
|
+
return context.payload.repository ? `${context.payload.repository?.html_url}/actions/runs/${context.runId}` : "http://localhost";
|
|
487
550
|
}
|
|
488
551
|
};
|
|
489
552
|
var DenoRuntimeInfo = class extends PluginRuntimeInfo {
|
|
@@ -573,14 +636,23 @@ function getPluginOptions(options) {
|
|
|
573
636
|
}
|
|
574
637
|
|
|
575
638
|
// src/comment.ts
|
|
639
|
+
function logByStatus2(logger, message, status, metadata) {
|
|
640
|
+
const payload = { ...metadata, ...status ? { status } : {} };
|
|
641
|
+
if (status && status >= 500) return logger.error(message, payload);
|
|
642
|
+
if (status && status >= 400) return logger.warn(message, payload);
|
|
643
|
+
if (status && status >= 300) return logger.debug(message, payload);
|
|
644
|
+
if (status && status >= 200) return logger.ok(message, payload);
|
|
645
|
+
if (status && status >= 100) return logger.info(message, payload);
|
|
646
|
+
return logger.error(message, payload);
|
|
647
|
+
}
|
|
576
648
|
var CommentHandler = class _CommentHandler {
|
|
577
649
|
static HEADER_NAME = "UbiquityOS";
|
|
578
650
|
_lastCommentId = { reviewCommentId: null, issueCommentId: null };
|
|
579
|
-
async _updateIssueComment(
|
|
651
|
+
async _updateIssueComment(context, params) {
|
|
580
652
|
if (!this._lastCommentId.issueCommentId) {
|
|
581
|
-
throw
|
|
653
|
+
throw context.logger.error("issueCommentId is missing");
|
|
582
654
|
}
|
|
583
|
-
const commentData = await
|
|
655
|
+
const commentData = await context.octokit.rest.issues.updateComment({
|
|
584
656
|
owner: params.owner,
|
|
585
657
|
repo: params.repo,
|
|
586
658
|
comment_id: this._lastCommentId.issueCommentId,
|
|
@@ -588,11 +660,11 @@ var CommentHandler = class _CommentHandler {
|
|
|
588
660
|
});
|
|
589
661
|
return { ...commentData.data, issueNumber: params.issueNumber };
|
|
590
662
|
}
|
|
591
|
-
async _updateReviewComment(
|
|
663
|
+
async _updateReviewComment(context, params) {
|
|
592
664
|
if (!this._lastCommentId.reviewCommentId) {
|
|
593
|
-
throw
|
|
665
|
+
throw context.logger.error("reviewCommentId is missing");
|
|
594
666
|
}
|
|
595
|
-
const commentData = await
|
|
667
|
+
const commentData = await context.octokit.rest.pulls.updateReviewComment({
|
|
596
668
|
owner: params.owner,
|
|
597
669
|
repo: params.repo,
|
|
598
670
|
comment_id: this._lastCommentId.reviewCommentId,
|
|
@@ -600,9 +672,9 @@ var CommentHandler = class _CommentHandler {
|
|
|
600
672
|
});
|
|
601
673
|
return { ...commentData.data, issueNumber: params.issueNumber };
|
|
602
674
|
}
|
|
603
|
-
async _createNewComment(
|
|
675
|
+
async _createNewComment(context, params) {
|
|
604
676
|
if (params.commentId) {
|
|
605
|
-
const commentData2 = await
|
|
677
|
+
const commentData2 = await context.octokit.rest.pulls.createReplyForReviewComment({
|
|
606
678
|
owner: params.owner,
|
|
607
679
|
repo: params.repo,
|
|
608
680
|
pull_number: params.issueNumber,
|
|
@@ -612,7 +684,7 @@ var CommentHandler = class _CommentHandler {
|
|
|
612
684
|
this._lastCommentId.reviewCommentId = commentData2.data.id;
|
|
613
685
|
return { ...commentData2.data, issueNumber: params.issueNumber };
|
|
614
686
|
}
|
|
615
|
-
const commentData = await
|
|
687
|
+
const commentData = await context.octokit.rest.issues.createComment({
|
|
616
688
|
owner: params.owner,
|
|
617
689
|
repo: params.repo,
|
|
618
690
|
issue_number: params.issueNumber,
|
|
@@ -621,54 +693,58 @@ var CommentHandler = class _CommentHandler {
|
|
|
621
693
|
this._lastCommentId.issueCommentId = commentData.data.id;
|
|
622
694
|
return { ...commentData.data, issueNumber: params.issueNumber };
|
|
623
695
|
}
|
|
624
|
-
_getIssueNumber(
|
|
625
|
-
if ("issue" in
|
|
626
|
-
if ("pull_request" in
|
|
627
|
-
if ("discussion" in
|
|
696
|
+
_getIssueNumber(context) {
|
|
697
|
+
if ("issue" in context.payload) return context.payload.issue.number;
|
|
698
|
+
if ("pull_request" in context.payload) return context.payload.pull_request.number;
|
|
699
|
+
if ("discussion" in context.payload) return context.payload.discussion.number;
|
|
628
700
|
return void 0;
|
|
629
701
|
}
|
|
630
|
-
_getCommentId(
|
|
631
|
-
return "pull_request" in
|
|
702
|
+
_getCommentId(context) {
|
|
703
|
+
return "pull_request" in context.payload && "comment" in context.payload ? context.payload.comment.id : void 0;
|
|
632
704
|
}
|
|
633
|
-
_extractIssueContext(
|
|
634
|
-
if (!("repository" in
|
|
705
|
+
_extractIssueContext(context) {
|
|
706
|
+
if (!("repository" in context.payload) || !context.payload.repository?.owner?.login) {
|
|
635
707
|
return null;
|
|
636
708
|
}
|
|
637
|
-
const issueNumber = this._getIssueNumber(
|
|
709
|
+
const issueNumber = this._getIssueNumber(context);
|
|
638
710
|
if (!issueNumber) return null;
|
|
639
711
|
return {
|
|
640
712
|
issueNumber,
|
|
641
|
-
commentId: this._getCommentId(
|
|
642
|
-
owner:
|
|
643
|
-
repo:
|
|
713
|
+
commentId: this._getCommentId(context),
|
|
714
|
+
owner: context.payload.repository.owner.login,
|
|
715
|
+
repo: context.payload.repository.name
|
|
644
716
|
};
|
|
645
717
|
}
|
|
646
|
-
_processMessage(
|
|
718
|
+
_processMessage(context, message) {
|
|
647
719
|
if (message instanceof Error) {
|
|
648
720
|
const metadata2 = {
|
|
649
721
|
message: message.message,
|
|
650
722
|
name: message.name,
|
|
651
723
|
stack: message.stack
|
|
652
724
|
};
|
|
653
|
-
|
|
725
|
+
const status = getErrorStatus(message);
|
|
726
|
+
const logReturn = logByStatus2(context.logger, message.message, status, metadata2);
|
|
727
|
+
return { metadata: { ...metadata2, ...status ? { status } : {} }, logMessage: logReturn.logMessage };
|
|
654
728
|
}
|
|
729
|
+
const stackLine = message.metadata?.error?.stack?.split("\n")[2];
|
|
730
|
+
const callerMatch = stackLine ? /at (\S+)/.exec(stackLine) : null;
|
|
655
731
|
const metadata = message.metadata ? {
|
|
656
732
|
...message.metadata,
|
|
657
733
|
message: message.metadata.message,
|
|
658
734
|
stack: message.metadata.stack || message.metadata.error?.stack,
|
|
659
|
-
caller: message.metadata.caller ||
|
|
735
|
+
caller: message.metadata.caller || callerMatch?.[1]
|
|
660
736
|
} : { ...message };
|
|
661
737
|
return { metadata, logMessage: message.logMessage };
|
|
662
738
|
}
|
|
663
|
-
_getInstigatorName(
|
|
664
|
-
if ("installation" in
|
|
665
|
-
return
|
|
739
|
+
_getInstigatorName(context) {
|
|
740
|
+
if ("installation" in context.payload && context.payload.installation && "account" in context.payload.installation && context.payload.installation?.account?.name) {
|
|
741
|
+
return context.payload.installation?.account?.name;
|
|
666
742
|
}
|
|
667
|
-
return
|
|
743
|
+
return context.payload.sender?.login || _CommentHandler.HEADER_NAME;
|
|
668
744
|
}
|
|
669
|
-
_createMetadataContent(
|
|
745
|
+
_createMetadataContent(context, metadata) {
|
|
670
746
|
const jsonPretty = sanitizeMetadata(metadata);
|
|
671
|
-
const instigatorName = this._getInstigatorName(
|
|
747
|
+
const instigatorName = this._getInstigatorName(context);
|
|
672
748
|
const runUrl = PluginRuntimeInfo.getInstance().runUrl;
|
|
673
749
|
const version = PluginRuntimeInfo.getInstance().version;
|
|
674
750
|
const callingFnName = metadata.caller || "anonymous";
|
|
@@ -685,63 +761,39 @@ var CommentHandler = class _CommentHandler {
|
|
|
685
761
|
/*
|
|
686
762
|
* Creates the body for the comment, embeds the metadata and the header hidden in the body as well.
|
|
687
763
|
*/
|
|
688
|
-
createCommentBody(
|
|
689
|
-
return this._createCommentBody(
|
|
764
|
+
createCommentBody(context, message, options) {
|
|
765
|
+
return this._createCommentBody(context, message, options);
|
|
690
766
|
}
|
|
691
|
-
_createCommentBody(
|
|
692
|
-
const { metadata, logMessage } = this._processMessage(
|
|
693
|
-
const { header, jsonPretty } = this._createMetadataContent(
|
|
767
|
+
_createCommentBody(context, message, options) {
|
|
768
|
+
const { metadata, logMessage } = this._processMessage(context, message);
|
|
769
|
+
const { header, jsonPretty } = this._createMetadataContent(context, metadata);
|
|
694
770
|
const metadataContent = this._formatMetadataContent(logMessage, header, jsonPretty);
|
|
695
771
|
return `${options?.raw ? logMessage?.raw : logMessage?.diff}
|
|
696
772
|
|
|
697
773
|
${metadataContent}
|
|
698
774
|
`;
|
|
699
775
|
}
|
|
700
|
-
async postComment(
|
|
701
|
-
const issueContext = this._extractIssueContext(
|
|
776
|
+
async postComment(context, message, options = { updateComment: true, raw: false }) {
|
|
777
|
+
const issueContext = this._extractIssueContext(context);
|
|
702
778
|
if (!issueContext) {
|
|
703
|
-
|
|
779
|
+
context.logger.warn("Cannot post comment: missing issue context in payload");
|
|
704
780
|
return null;
|
|
705
781
|
}
|
|
706
|
-
const body = this._createCommentBody(
|
|
782
|
+
const body = this._createCommentBody(context, message, options);
|
|
707
783
|
const { issueNumber, commentId, owner, repo } = issueContext;
|
|
708
784
|
const params = { owner, repo, body, issueNumber };
|
|
709
785
|
if (options.updateComment) {
|
|
710
|
-
if (this._lastCommentId.issueCommentId && !("pull_request" in
|
|
711
|
-
return this._updateIssueComment(
|
|
786
|
+
if (this._lastCommentId.issueCommentId && !("pull_request" in context.payload && "comment" in context.payload)) {
|
|
787
|
+
return this._updateIssueComment(context, params);
|
|
712
788
|
}
|
|
713
|
-
if (this._lastCommentId.reviewCommentId && "pull_request" in
|
|
714
|
-
return this._updateReviewComment(
|
|
789
|
+
if (this._lastCommentId.reviewCommentId && "pull_request" in context.payload && "comment" in context.payload) {
|
|
790
|
+
return this._updateReviewComment(context, params);
|
|
715
791
|
}
|
|
716
792
|
}
|
|
717
|
-
return this._createNewComment(
|
|
793
|
+
return this._createNewComment(context, { ...params, commentId });
|
|
718
794
|
}
|
|
719
795
|
};
|
|
720
796
|
|
|
721
|
-
// src/error.ts
|
|
722
|
-
function transformError(context2, error) {
|
|
723
|
-
let loggerError;
|
|
724
|
-
if (error instanceof AggregateError) {
|
|
725
|
-
loggerError = context2.logger.error(
|
|
726
|
-
error.errors.map((err) => {
|
|
727
|
-
if (err instanceof LogReturn) {
|
|
728
|
-
return err.logMessage.raw;
|
|
729
|
-
} else if (err instanceof Error) {
|
|
730
|
-
return err.message;
|
|
731
|
-
} else {
|
|
732
|
-
return err;
|
|
733
|
-
}
|
|
734
|
-
}).join("\n\n"),
|
|
735
|
-
{ error }
|
|
736
|
-
);
|
|
737
|
-
} else if (error instanceof Error || error instanceof LogReturn) {
|
|
738
|
-
loggerError = error;
|
|
739
|
-
} else {
|
|
740
|
-
loggerError = context2.logger.error(String(error));
|
|
741
|
-
}
|
|
742
|
-
return loggerError;
|
|
743
|
-
}
|
|
744
|
-
|
|
745
797
|
// src/helpers/command.ts
|
|
746
798
|
var import_value = require("@sinclair/typebox/value");
|
|
747
799
|
function getCommand(inputs, pluginOptions) {
|
|
@@ -974,7 +1026,7 @@ async function verifySignature(publicKeyPem, inputs, signature) {
|
|
|
974
1026
|
ref: inputs.ref,
|
|
975
1027
|
command: inputs.command
|
|
976
1028
|
};
|
|
977
|
-
const pemContents = publicKeyPem.replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", "").
|
|
1029
|
+
const pemContents = publicKeyPem.replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", "").replace(/\s+/g, "");
|
|
978
1030
|
const binaryDer = Uint8Array.from(atob(pemContents), (c) => c.charCodeAt(0));
|
|
979
1031
|
const publicKey = await crypto.subtle.importKey(
|
|
980
1032
|
"spki",
|
|
@@ -1027,16 +1079,12 @@ var inputSchema = import_typebox3.Type.Object({
|
|
|
1027
1079
|
|
|
1028
1080
|
// src/actions.ts
|
|
1029
1081
|
(0, import_dotenv.config)();
|
|
1030
|
-
async function handleError(
|
|
1082
|
+
async function handleError(context, pluginOptions, error) {
|
|
1031
1083
|
console.error(error);
|
|
1032
|
-
const loggerError = transformError(
|
|
1033
|
-
|
|
1034
|
-
core.setFailed(loggerError.logMessage.diff);
|
|
1035
|
-
} else if (loggerError instanceof Error) {
|
|
1036
|
-
core.setFailed(loggerError);
|
|
1037
|
-
}
|
|
1084
|
+
const loggerError = transformError(context, error);
|
|
1085
|
+
core.setFailed(loggerError.logMessage.diff);
|
|
1038
1086
|
if (pluginOptions.postCommentOnError && loggerError) {
|
|
1039
|
-
await
|
|
1087
|
+
await context.commentHandler.postComment(context, loggerError);
|
|
1040
1088
|
}
|
|
1041
1089
|
}
|
|
1042
1090
|
async function createActionsPlugin(handler, options) {
|
|
@@ -1046,7 +1094,8 @@ async function createActionsPlugin(handler, options) {
|
|
|
1046
1094
|
core.setFailed("Error: PLUGIN_GITHUB_TOKEN env is not set");
|
|
1047
1095
|
return;
|
|
1048
1096
|
}
|
|
1049
|
-
const
|
|
1097
|
+
const githubContext = getGithubContext();
|
|
1098
|
+
const body = githubContext.payload.inputs;
|
|
1050
1099
|
const inputSchemaErrors = [...import_value3.Value.Errors(inputSchema, body)];
|
|
1051
1100
|
if (inputSchemaErrors.length) {
|
|
1052
1101
|
console.dir(inputSchemaErrors, { depth: null });
|
|
@@ -1084,7 +1133,7 @@ async function createActionsPlugin(handler, options) {
|
|
|
1084
1133
|
env2 = process.env;
|
|
1085
1134
|
}
|
|
1086
1135
|
const command = getCommand(inputs, pluginOptions);
|
|
1087
|
-
const
|
|
1136
|
+
const context = {
|
|
1088
1137
|
eventName: inputs.eventName,
|
|
1089
1138
|
payload: inputs.eventPayload,
|
|
1090
1139
|
command,
|
|
@@ -1097,20 +1146,21 @@ async function createActionsPlugin(handler, options) {
|
|
|
1097
1146
|
commentHandler: new CommentHandler()
|
|
1098
1147
|
};
|
|
1099
1148
|
try {
|
|
1100
|
-
const result = await handler(
|
|
1149
|
+
const result = await handler(context);
|
|
1101
1150
|
core.setOutput("result", result);
|
|
1102
1151
|
if (pluginOptions?.returnDataToKernel) {
|
|
1103
1152
|
await returnDataToKernel(pluginGithubToken, inputs.stateId, result);
|
|
1104
1153
|
}
|
|
1105
1154
|
} catch (error) {
|
|
1106
|
-
await handleError(
|
|
1155
|
+
await handleError(context, pluginOptions, error);
|
|
1107
1156
|
}
|
|
1108
1157
|
}
|
|
1109
1158
|
async function returnDataToKernel(repoToken, stateId, output) {
|
|
1159
|
+
const githubContext = getGithubContext();
|
|
1110
1160
|
const octokit = new customOctokit({ auth: repoToken });
|
|
1111
1161
|
await octokit.rest.repos.createDispatchEvent({
|
|
1112
|
-
owner:
|
|
1113
|
-
repo:
|
|
1162
|
+
owner: githubContext.repo.owner,
|
|
1163
|
+
repo: githubContext.repo.repo,
|
|
1114
1164
|
event_type: "return-data-to-ubiquity-os-kernel",
|
|
1115
1165
|
client_payload: {
|
|
1116
1166
|
state_id: stateId,
|
|
@@ -1177,7 +1227,7 @@ var import_value4 = require("@sinclair/typebox/value");
|
|
|
1177
1227
|
|
|
1178
1228
|
// ../../node_modules/hono/dist/compose.js
|
|
1179
1229
|
var compose = (middleware, onError, onNotFound) => {
|
|
1180
|
-
return (
|
|
1230
|
+
return (context, next) => {
|
|
1181
1231
|
let index = -1;
|
|
1182
1232
|
return dispatch(0);
|
|
1183
1233
|
async function dispatch(i) {
|
|
@@ -1190,31 +1240,31 @@ var compose = (middleware, onError, onNotFound) => {
|
|
|
1190
1240
|
let handler;
|
|
1191
1241
|
if (middleware[i]) {
|
|
1192
1242
|
handler = middleware[i][0][0];
|
|
1193
|
-
|
|
1243
|
+
context.req.routeIndex = i;
|
|
1194
1244
|
} else {
|
|
1195
1245
|
handler = i === middleware.length && next || void 0;
|
|
1196
1246
|
}
|
|
1197
1247
|
if (handler) {
|
|
1198
1248
|
try {
|
|
1199
|
-
res = await handler(
|
|
1249
|
+
res = await handler(context, () => dispatch(i + 1));
|
|
1200
1250
|
} catch (err) {
|
|
1201
1251
|
if (err instanceof Error && onError) {
|
|
1202
|
-
|
|
1203
|
-
res = await onError(err,
|
|
1252
|
+
context.error = err;
|
|
1253
|
+
res = await onError(err, context);
|
|
1204
1254
|
isError = true;
|
|
1205
1255
|
} else {
|
|
1206
1256
|
throw err;
|
|
1207
1257
|
}
|
|
1208
1258
|
}
|
|
1209
1259
|
} else {
|
|
1210
|
-
if (
|
|
1211
|
-
res = await onNotFound(
|
|
1260
|
+
if (context.finalized === false && onNotFound) {
|
|
1261
|
+
res = await onNotFound(context);
|
|
1212
1262
|
}
|
|
1213
1263
|
}
|
|
1214
|
-
if (res && (
|
|
1215
|
-
|
|
1264
|
+
if (res && (context.finalized === false || isError)) {
|
|
1265
|
+
context.res = res;
|
|
1216
1266
|
}
|
|
1217
|
-
return
|
|
1267
|
+
return context;
|
|
1218
1268
|
}
|
|
1219
1269
|
};
|
|
1220
1270
|
};
|
|
@@ -1616,7 +1666,7 @@ var raw = (value, callbacks) => {
|
|
|
1616
1666
|
escapedString.callbacks = callbacks;
|
|
1617
1667
|
return escapedString;
|
|
1618
1668
|
};
|
|
1619
|
-
var resolveCallback = async (str, phase, preserveCallbacks,
|
|
1669
|
+
var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => {
|
|
1620
1670
|
if (typeof str === "object" && !(str instanceof String)) {
|
|
1621
1671
|
if (!(str instanceof Promise)) {
|
|
1622
1672
|
str = str.toString();
|
|
@@ -1634,9 +1684,9 @@ var resolveCallback = async (str, phase, preserveCallbacks, context2, buffer) =>
|
|
|
1634
1684
|
} else {
|
|
1635
1685
|
buffer = [str];
|
|
1636
1686
|
}
|
|
1637
|
-
const resStr = Promise.all(callbacks.map((c) => c({ phase, buffer, context
|
|
1687
|
+
const resStr = Promise.all(callbacks.map((c) => c({ phase, buffer, context }))).then(
|
|
1638
1688
|
(res) => Promise.all(
|
|
1639
|
-
res.filter(Boolean).map((str2) => resolveCallback(str2, phase, false,
|
|
1689
|
+
res.filter(Boolean).map((str2) => resolveCallback(str2, phase, false, context, buffer))
|
|
1640
1690
|
).then(() => buffer[0])
|
|
1641
1691
|
);
|
|
1642
1692
|
if (preserveCallbacks) {
|
|
@@ -2029,13 +2079,13 @@ var Hono = class {
|
|
|
2029
2079
|
const composed = compose(matchResult[0], this.errorHandler, this.#notFoundHandler);
|
|
2030
2080
|
return (async () => {
|
|
2031
2081
|
try {
|
|
2032
|
-
const
|
|
2033
|
-
if (!
|
|
2082
|
+
const context = await composed(c);
|
|
2083
|
+
if (!context.finalized) {
|
|
2034
2084
|
throw new Error(
|
|
2035
2085
|
"Context is not finalized. Did you forget to return a Response object or `await next()`?"
|
|
2036
2086
|
);
|
|
2037
2087
|
}
|
|
2038
|
-
return
|
|
2088
|
+
return context.res;
|
|
2039
2089
|
} catch (err) {
|
|
2040
2090
|
return this.#handleError(err, c);
|
|
2041
2091
|
}
|
|
@@ -2094,7 +2144,7 @@ var Node = class {
|
|
|
2094
2144
|
#index;
|
|
2095
2145
|
#varIndex;
|
|
2096
2146
|
#children = /* @__PURE__ */ Object.create(null);
|
|
2097
|
-
insert(tokens, index, paramMap,
|
|
2147
|
+
insert(tokens, index, paramMap, context, pathErrorCheckOnly) {
|
|
2098
2148
|
if (tokens.length === 0) {
|
|
2099
2149
|
if (this.#index !== void 0) {
|
|
2100
2150
|
throw PATH_ERROR;
|
|
@@ -2132,7 +2182,7 @@ var Node = class {
|
|
|
2132
2182
|
}
|
|
2133
2183
|
node = this.#children[regexpStr] = new Node();
|
|
2134
2184
|
if (name !== "") {
|
|
2135
|
-
node.#varIndex =
|
|
2185
|
+
node.#varIndex = context.varIndex++;
|
|
2136
2186
|
}
|
|
2137
2187
|
}
|
|
2138
2188
|
if (!pathErrorCheckOnly && name !== "") {
|
|
@@ -2152,7 +2202,7 @@ var Node = class {
|
|
|
2152
2202
|
node = this.#children[token] = new Node();
|
|
2153
2203
|
}
|
|
2154
2204
|
}
|
|
2155
|
-
node.insert(restTokens, index, paramMap,
|
|
2205
|
+
node.insert(restTokens, index, paramMap, context, pathErrorCheckOnly);
|
|
2156
2206
|
}
|
|
2157
2207
|
buildRegExpStr() {
|
|
2158
2208
|
const childKeys = Object.keys(this.#children).sort(compareKey);
|
|
@@ -2694,11 +2744,11 @@ var HTTPException = class extends Error {
|
|
|
2694
2744
|
};
|
|
2695
2745
|
|
|
2696
2746
|
// src/server.ts
|
|
2697
|
-
async function handleError2(
|
|
2747
|
+
async function handleError2(context, pluginOptions, error) {
|
|
2698
2748
|
console.error(error);
|
|
2699
|
-
const loggerError = transformError(
|
|
2749
|
+
const loggerError = transformError(context, error);
|
|
2700
2750
|
if (pluginOptions.postCommentOnError && loggerError) {
|
|
2701
|
-
await
|
|
2751
|
+
await context.commentHandler.postComment(context, loggerError);
|
|
2702
2752
|
}
|
|
2703
2753
|
throw new HTTPException(500, { message: "Unexpected error" });
|
|
2704
2754
|
}
|
|
@@ -2749,7 +2799,7 @@ function createPlugin(handler, manifest, options) {
|
|
|
2749
2799
|
const workerName = new URL(inputs.ref).hostname.split(".")[0];
|
|
2750
2800
|
PluginRuntimeInfo.getInstance({ ...env2, CLOUDFLARE_WORKER_NAME: workerName });
|
|
2751
2801
|
const command = getCommand(inputs, pluginOptions);
|
|
2752
|
-
const
|
|
2802
|
+
const context = {
|
|
2753
2803
|
eventName: inputs.eventName,
|
|
2754
2804
|
payload: inputs.eventPayload,
|
|
2755
2805
|
command,
|
|
@@ -2762,96 +2812,195 @@ function createPlugin(handler, manifest, options) {
|
|
|
2762
2812
|
commentHandler: new CommentHandler()
|
|
2763
2813
|
};
|
|
2764
2814
|
try {
|
|
2765
|
-
const result = await handler(
|
|
2815
|
+
const result = await handler(context);
|
|
2766
2816
|
return ctx.json({ stateId: inputs.stateId, output: result ?? {} });
|
|
2767
2817
|
} catch (error) {
|
|
2768
|
-
await handleError2(
|
|
2818
|
+
await handleError2(context, pluginOptions, error);
|
|
2769
2819
|
}
|
|
2770
2820
|
});
|
|
2771
2821
|
return app;
|
|
2772
2822
|
}
|
|
2773
2823
|
|
|
2774
2824
|
// src/llm/index.ts
|
|
2825
|
+
var EMPTY_STRING = "";
|
|
2775
2826
|
function normalizeBaseUrl(baseUrl) {
|
|
2776
|
-
|
|
2827
|
+
let normalized = baseUrl.trim();
|
|
2828
|
+
while (normalized.endsWith("/")) {
|
|
2829
|
+
normalized = normalized.slice(0, -1);
|
|
2830
|
+
}
|
|
2831
|
+
return normalized;
|
|
2832
|
+
}
|
|
2833
|
+
var MAX_LLM_RETRIES = 2;
|
|
2834
|
+
var RETRY_BACKOFF_MS = [250, 750];
|
|
2835
|
+
function getRetryDelayMs(attempt) {
|
|
2836
|
+
return RETRY_BACKOFF_MS[Math.min(attempt, RETRY_BACKOFF_MS.length - 1)] ?? 750;
|
|
2837
|
+
}
|
|
2838
|
+
function sleep(ms) {
|
|
2839
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2777
2840
|
}
|
|
2778
2841
|
function getEnvString(name) {
|
|
2779
|
-
if (typeof process === "undefined" || !process?.env) return
|
|
2780
|
-
return String(process.env[name] ??
|
|
2842
|
+
if (typeof process === "undefined" || !process?.env) return EMPTY_STRING;
|
|
2843
|
+
return String(process.env[name] ?? EMPTY_STRING).trim();
|
|
2781
2844
|
}
|
|
2782
2845
|
function getAiBaseUrl(options) {
|
|
2783
2846
|
if (typeof options.baseUrl === "string" && options.baseUrl.trim()) {
|
|
2784
2847
|
return normalizeBaseUrl(options.baseUrl);
|
|
2785
2848
|
}
|
|
2786
|
-
const envBaseUrl = getEnvString("
|
|
2849
|
+
const envBaseUrl = getEnvString("UOS_AI_URL") || getEnvString("UOS_AI_BASE_URL");
|
|
2787
2850
|
if (envBaseUrl) return normalizeBaseUrl(envBaseUrl);
|
|
2788
|
-
return "https://ai
|
|
2851
|
+
return "https://ai-ubq-fi.deno.dev";
|
|
2789
2852
|
}
|
|
2790
2853
|
async function callLlm(options, input) {
|
|
2791
|
-
const authToken = input
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
const
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
}
|
|
2802
|
-
|
|
2803
|
-
const
|
|
2854
|
+
const authToken = String(input.authToken ?? EMPTY_STRING).trim();
|
|
2855
|
+
if (!authToken) {
|
|
2856
|
+
const err = new Error("Missing authToken in input");
|
|
2857
|
+
err.status = 401;
|
|
2858
|
+
throw err;
|
|
2859
|
+
}
|
|
2860
|
+
const kernelToken = "ubiquityKernelToken" in input ? input.ubiquityKernelToken : void 0;
|
|
2861
|
+
const payload = getPayload(input);
|
|
2862
|
+
const { owner, repo, installationId } = getRepoMetadata(payload);
|
|
2863
|
+
ensureKernelToken(authToken, kernelToken);
|
|
2864
|
+
const { baseUrl, model, stream: isStream, messages, ...rest } = options;
|
|
2865
|
+
ensureMessages(messages);
|
|
2866
|
+
const url = buildAiUrl(options, baseUrl);
|
|
2804
2867
|
const body = JSON.stringify({
|
|
2805
2868
|
...rest,
|
|
2806
2869
|
...model ? { model } : {},
|
|
2807
2870
|
messages,
|
|
2808
|
-
stream:
|
|
2871
|
+
stream: isStream ?? false
|
|
2809
2872
|
});
|
|
2873
|
+
const headers = buildHeaders(authToken, {
|
|
2874
|
+
owner,
|
|
2875
|
+
repo,
|
|
2876
|
+
installationId,
|
|
2877
|
+
ubiquityKernelToken: kernelToken
|
|
2878
|
+
});
|
|
2879
|
+
const response = await fetchWithRetry(url, { method: "POST", headers, body }, MAX_LLM_RETRIES);
|
|
2880
|
+
if (isStream) {
|
|
2881
|
+
if (!response.body) {
|
|
2882
|
+
throw new Error("LLM API error: missing response body for streaming request");
|
|
2883
|
+
}
|
|
2884
|
+
return parseSseStream(response.body);
|
|
2885
|
+
}
|
|
2886
|
+
return response.json();
|
|
2887
|
+
}
|
|
2888
|
+
function ensureKernelToken(authToken, kernelToken) {
|
|
2889
|
+
const isKernelTokenRequired = authToken.startsWith("gh");
|
|
2890
|
+
if (isKernelTokenRequired && !kernelToken) {
|
|
2891
|
+
const err = new Error("Missing ubiquityKernelToken in input (kernel attestation is required for GitHub auth)");
|
|
2892
|
+
err.status = 401;
|
|
2893
|
+
throw err;
|
|
2894
|
+
}
|
|
2895
|
+
}
|
|
2896
|
+
function ensureMessages(messages) {
|
|
2897
|
+
if (!Array.isArray(messages) || messages.length === 0) {
|
|
2898
|
+
const err = new Error("messages must be a non-empty array");
|
|
2899
|
+
err.status = 400;
|
|
2900
|
+
throw err;
|
|
2901
|
+
}
|
|
2902
|
+
}
|
|
2903
|
+
function buildAiUrl(options, baseUrl) {
|
|
2904
|
+
return `${getAiBaseUrl({ ...options, baseUrl })}/v1/chat/completions`;
|
|
2905
|
+
}
|
|
2906
|
+
async function fetchWithRetry(url, options, maxRetries) {
|
|
2907
|
+
let attempt = 0;
|
|
2908
|
+
let lastError;
|
|
2909
|
+
while (attempt <= maxRetries) {
|
|
2910
|
+
try {
|
|
2911
|
+
const response = await fetch(url, options);
|
|
2912
|
+
if (response.ok) return response;
|
|
2913
|
+
const errText = await response.text();
|
|
2914
|
+
if (response.status >= 500 && attempt < maxRetries) {
|
|
2915
|
+
await sleep(getRetryDelayMs(attempt));
|
|
2916
|
+
attempt += 1;
|
|
2917
|
+
continue;
|
|
2918
|
+
}
|
|
2919
|
+
const error = new Error(`LLM API error: ${response.status} - ${errText}`);
|
|
2920
|
+
error.status = response.status;
|
|
2921
|
+
throw error;
|
|
2922
|
+
} catch (error) {
|
|
2923
|
+
lastError = error;
|
|
2924
|
+
if (attempt >= maxRetries) throw error;
|
|
2925
|
+
await sleep(getRetryDelayMs(attempt));
|
|
2926
|
+
attempt += 1;
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
throw lastError ?? new Error("LLM API error: request failed after retries");
|
|
2930
|
+
}
|
|
2931
|
+
function getPayload(input) {
|
|
2932
|
+
if ("payload" in input) {
|
|
2933
|
+
return input.payload;
|
|
2934
|
+
}
|
|
2935
|
+
return input.eventPayload;
|
|
2936
|
+
}
|
|
2937
|
+
function getRepoMetadata(payload) {
|
|
2938
|
+
const repoPayload = payload;
|
|
2939
|
+
return {
|
|
2940
|
+
owner: repoPayload?.repository?.owner?.login ?? EMPTY_STRING,
|
|
2941
|
+
repo: repoPayload?.repository?.name ?? EMPTY_STRING,
|
|
2942
|
+
installationId: repoPayload?.installation?.id
|
|
2943
|
+
};
|
|
2944
|
+
}
|
|
2945
|
+
function buildHeaders(authToken, options) {
|
|
2810
2946
|
const headers = {
|
|
2811
2947
|
Authorization: `Bearer ${authToken}`,
|
|
2812
2948
|
"Content-Type": "application/json"
|
|
2813
2949
|
};
|
|
2814
|
-
if (owner) headers["X-GitHub-Owner"] = owner;
|
|
2815
|
-
if (repo) headers["X-GitHub-Repo"] = repo;
|
|
2816
|
-
if (typeof installationId === "number" && Number.isFinite(installationId)) {
|
|
2817
|
-
headers["X-GitHub-Installation-Id"] = String(installationId);
|
|
2818
|
-
}
|
|
2819
|
-
if (ubiquityKernelToken) {
|
|
2820
|
-
headers["X-Ubiquity-Kernel-Token"] = ubiquityKernelToken;
|
|
2950
|
+
if (options.owner) headers["X-GitHub-Owner"] = options.owner;
|
|
2951
|
+
if (options.repo) headers["X-GitHub-Repo"] = options.repo;
|
|
2952
|
+
if (typeof options.installationId === "number" && Number.isFinite(options.installationId)) {
|
|
2953
|
+
headers["X-GitHub-Installation-Id"] = String(options.installationId);
|
|
2821
2954
|
}
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
const err = await response.text();
|
|
2825
|
-
throw new Error(`LLM API error: ${response.status} - ${err}`);
|
|
2826
|
-
}
|
|
2827
|
-
if (options.stream) {
|
|
2828
|
-
return parseSseStream(response.body);
|
|
2955
|
+
if (options.ubiquityKernelToken) {
|
|
2956
|
+
headers["X-Ubiquity-Kernel-Token"] = options.ubiquityKernelToken;
|
|
2829
2957
|
}
|
|
2830
|
-
return
|
|
2958
|
+
return headers;
|
|
2831
2959
|
}
|
|
2832
2960
|
async function* parseSseStream(body) {
|
|
2833
2961
|
const reader = body.getReader();
|
|
2834
2962
|
const decoder = new TextDecoder();
|
|
2835
|
-
let buffer =
|
|
2963
|
+
let buffer = EMPTY_STRING;
|
|
2836
2964
|
try {
|
|
2837
2965
|
while (true) {
|
|
2838
|
-
const { value, done } = await reader.read();
|
|
2839
|
-
if (
|
|
2966
|
+
const { value, done: isDone } = await reader.read();
|
|
2967
|
+
if (isDone) break;
|
|
2840
2968
|
buffer += decoder.decode(value, { stream: true });
|
|
2841
|
-
const events = buffer
|
|
2842
|
-
buffer =
|
|
2969
|
+
const { events, remainder } = splitSseEvents(buffer);
|
|
2970
|
+
buffer = remainder;
|
|
2843
2971
|
for (const event of events) {
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
}
|
|
2972
|
+
const data = getEventData(event);
|
|
2973
|
+
if (!data) continue;
|
|
2974
|
+
if (data.trim() === "[DONE]") return;
|
|
2975
|
+
yield parseEventData(data);
|
|
2849
2976
|
}
|
|
2850
2977
|
}
|
|
2851
2978
|
} finally {
|
|
2852
2979
|
reader.releaseLock();
|
|
2853
2980
|
}
|
|
2854
2981
|
}
|
|
2982
|
+
function splitSseEvents(buffer) {
|
|
2983
|
+
const normalized = buffer.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2984
|
+
const parts = normalized.split("\n\n");
|
|
2985
|
+
const remainder = parts.pop() ?? EMPTY_STRING;
|
|
2986
|
+
return { events: parts, remainder };
|
|
2987
|
+
}
|
|
2988
|
+
function getEventData(event) {
|
|
2989
|
+
if (!event.trim()) return null;
|
|
2990
|
+
const dataLines = event.split("\n").filter((line) => line.startsWith("data:"));
|
|
2991
|
+
if (!dataLines.length) return null;
|
|
2992
|
+
const data = dataLines.map((line) => line.startsWith("data: ") ? line.slice(6) : line.slice(5).replace(/^ /, EMPTY_STRING)).join("\n");
|
|
2993
|
+
return data || null;
|
|
2994
|
+
}
|
|
2995
|
+
function parseEventData(data) {
|
|
2996
|
+
try {
|
|
2997
|
+
return JSON.parse(data);
|
|
2998
|
+
} catch (error) {
|
|
2999
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3000
|
+
const preview = data.length > 200 ? `${data.slice(0, 200)}...` : data;
|
|
3001
|
+
throw new Error(`LLM stream parse error: ${message}. Data: ${preview}`);
|
|
3002
|
+
}
|
|
3003
|
+
}
|
|
2855
3004
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2856
3005
|
0 && (module.exports = {
|
|
2857
3006
|
CommentHandler,
|