@sentry/junior 0.5.0 → 0.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/bin/junior.mjs +11 -1
- package/dist/{bot-PFLNB5PC.js → bot-ZKMCCT3D.js} +5 -3
- package/dist/{chunk-WM5Z766B.js → chunk-56WI5Q7P.js} +90 -33
- package/dist/{chunk-3ENACZ27.js → chunk-JRKU55W5.js} +489 -261
- package/dist/chunk-KT5HARSN.js +164 -0
- package/dist/{chunk-ECEC25CR.js → chunk-QHKQ2AWX.js} +1 -1
- package/dist/{chunk-BKYYVLVN.js → chunk-RKOO42TW.js} +53 -489
- package/dist/chunk-VW26MOSO.js +522 -0
- package/dist/cli/check.d.ts +8 -0
- package/dist/cli/check.js +303 -0
- package/dist/cli/init.js +7 -0
- package/dist/cli/run.d.ts +2 -1
- package/dist/cli/run.js +9 -1
- package/dist/cli/snapshot-warmup.js +3 -2
- package/dist/handlers/queue-callback.js +6 -4
- package/dist/handlers/router.js +7 -5
- package/dist/handlers/webhooks.js +1 -1
- package/package.json +5 -5
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
discoverInstalledPluginPackageContent,
|
|
3
|
+
discoverProjectRoots
|
|
4
|
+
} from "./chunk-Z5E25LRN.js";
|
|
1
5
|
import {
|
|
2
6
|
logInfo,
|
|
3
7
|
logWarn,
|
|
@@ -5,14 +9,12 @@ import {
|
|
|
5
9
|
withSpan
|
|
6
10
|
} from "./chunk-PY4AI2GZ.js";
|
|
7
11
|
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} from "./chunk-Z5E25LRN.js";
|
|
12
|
+
parsePluginManifest
|
|
13
|
+
} from "./chunk-VW26MOSO.js";
|
|
11
14
|
|
|
12
15
|
// src/chat/plugins/registry.ts
|
|
13
16
|
import { readFileSync, readdirSync, statSync } from "fs";
|
|
14
17
|
import path2 from "path";
|
|
15
|
-
import { parse as parseYaml } from "yaml";
|
|
16
18
|
|
|
17
19
|
// src/chat/home.ts
|
|
18
20
|
import fs from "fs";
|
|
@@ -32,7 +34,7 @@ function pathExists(targetPath) {
|
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
36
|
function hasAnyDataMarkers(appDir) {
|
|
35
|
-
return pathExists(path.join(appDir, "SOUL.md"));
|
|
37
|
+
return pathExists(path.join(appDir, "SOUL.md")) || pathExists(path.join(appDir, "ABOUT.md"));
|
|
36
38
|
}
|
|
37
39
|
function scoreAppCandidate(appDir) {
|
|
38
40
|
let score = 0;
|
|
@@ -73,7 +75,10 @@ function resolveHomeDir(cwd = process.cwd(), options) {
|
|
|
73
75
|
if (pathExists(directApp) && hasAnyDataMarkers(directApp)) {
|
|
74
76
|
return directApp;
|
|
75
77
|
}
|
|
76
|
-
const candidates = resolveCandidateAppDirs(
|
|
78
|
+
const candidates = resolveCandidateAppDirs(
|
|
79
|
+
resolvedCwd,
|
|
80
|
+
options?.projectRoots
|
|
81
|
+
);
|
|
77
82
|
if (candidates.length === 0) {
|
|
78
83
|
return directApp;
|
|
79
84
|
}
|
|
@@ -96,10 +101,7 @@ function resolveContentRoots(subdir) {
|
|
|
96
101
|
if (subdir === "data") {
|
|
97
102
|
return [homeDir()];
|
|
98
103
|
}
|
|
99
|
-
|
|
100
|
-
return [path.join(homeDir(), "skills"), path.resolve(process.cwd(), "skills")];
|
|
101
|
-
}
|
|
102
|
-
return [path.join(homeDir(), "plugins")];
|
|
104
|
+
return [path.join(homeDir(), subdir)];
|
|
103
105
|
}
|
|
104
106
|
function dataRoots() {
|
|
105
107
|
return unique(resolveContentRoots("data"));
|
|
@@ -114,6 +116,10 @@ function soulPathCandidates() {
|
|
|
114
116
|
const candidates = dataRoots().map((root) => path.join(root, "SOUL.md"));
|
|
115
117
|
return unique(candidates);
|
|
116
118
|
}
|
|
119
|
+
function aboutPathCandidates() {
|
|
120
|
+
const candidates = dataRoots().map((root) => path.join(root, "ABOUT.md"));
|
|
121
|
+
return unique(candidates);
|
|
122
|
+
}
|
|
117
123
|
|
|
118
124
|
// src/chat/plugins/github-app-broker.ts
|
|
119
125
|
import { createPrivateKey, createSign, randomUUID } from "crypto";
|
|
@@ -556,477 +562,6 @@ function createOAuthBearerBroker(manifest, credentials, deps) {
|
|
|
556
562
|
}
|
|
557
563
|
|
|
558
564
|
// src/chat/plugins/registry.ts
|
|
559
|
-
var PLUGIN_NAME_RE = /^[a-z][a-z0-9-]*$/;
|
|
560
|
-
var SHORT_CAPABILITY_RE = /^[a-z0-9]+(\.[a-z0-9-]+)*$/;
|
|
561
|
-
var SHORT_CONFIG_KEY_RE = /^[a-z0-9]+(\.[a-z0-9-]+)*$/;
|
|
562
|
-
var AUTH_TOKEN_ENV_RE = /^[A-Z][A-Z0-9_]*$/;
|
|
563
|
-
var API_DOMAIN_RE = /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
564
|
-
var RUNTIME_POSTINSTALL_CMD_RE = /^[A-Za-z0-9._/-]+$/;
|
|
565
|
-
var RESERVED_AUTHORIZE_PARAM_KEYS = /* @__PURE__ */ new Set([
|
|
566
|
-
"client_id",
|
|
567
|
-
"scope",
|
|
568
|
-
"state",
|
|
569
|
-
"redirect_uri",
|
|
570
|
-
"response_type"
|
|
571
|
-
]);
|
|
572
|
-
var FORBIDDEN_API_HEADER_NAMES = /* @__PURE__ */ new Set(["authorization"]);
|
|
573
|
-
var FORBIDDEN_TOKEN_HEADER_NAMES = /* @__PURE__ */ new Set(["authorization"]);
|
|
574
|
-
function toRecord(value, errorMessage) {
|
|
575
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
576
|
-
throw new Error(errorMessage);
|
|
577
|
-
}
|
|
578
|
-
return value;
|
|
579
|
-
}
|
|
580
|
-
function requireStringField(record, field, errorMessage) {
|
|
581
|
-
const value = record[field];
|
|
582
|
-
if (typeof value !== "string" || !value.trim()) {
|
|
583
|
-
throw new Error(errorMessage);
|
|
584
|
-
}
|
|
585
|
-
return value.trim();
|
|
586
|
-
}
|
|
587
|
-
function requireEnvVarField(record, field, pluginName) {
|
|
588
|
-
const value = requireStringField(
|
|
589
|
-
record,
|
|
590
|
-
field,
|
|
591
|
-
`Plugin ${pluginName} ${field} must be a non-empty string`
|
|
592
|
-
);
|
|
593
|
-
if (!AUTH_TOKEN_ENV_RE.test(value)) {
|
|
594
|
-
throw new Error(
|
|
595
|
-
`Plugin ${pluginName} ${field} must be an uppercase env var name`
|
|
596
|
-
);
|
|
597
|
-
}
|
|
598
|
-
return value;
|
|
599
|
-
}
|
|
600
|
-
function requireHttpsUrlField(record, field, pluginName) {
|
|
601
|
-
const value = requireStringField(
|
|
602
|
-
record,
|
|
603
|
-
field,
|
|
604
|
-
`Plugin ${pluginName} oauth.${field} must be a non-empty string`
|
|
605
|
-
);
|
|
606
|
-
let parsed;
|
|
607
|
-
try {
|
|
608
|
-
parsed = new URL(value);
|
|
609
|
-
} catch {
|
|
610
|
-
throw new Error(`Plugin ${pluginName} oauth.${field} must be a valid URL`);
|
|
611
|
-
}
|
|
612
|
-
if (parsed.protocol !== "https:") {
|
|
613
|
-
throw new Error(`Plugin ${pluginName} oauth.${field} must use https`);
|
|
614
|
-
}
|
|
615
|
-
return value;
|
|
616
|
-
}
|
|
617
|
-
function normalizeApiDomain(rawDomain, name) {
|
|
618
|
-
const domain = typeof rawDomain === "string" ? rawDomain.trim().toLowerCase() : "";
|
|
619
|
-
if (!domain) {
|
|
620
|
-
throw new Error(
|
|
621
|
-
`Plugin ${name} credentials.api-domains entries must be non-empty strings`
|
|
622
|
-
);
|
|
623
|
-
}
|
|
624
|
-
if (!API_DOMAIN_RE.test(domain)) {
|
|
625
|
-
throw new Error(
|
|
626
|
-
`Plugin ${name} credentials.api-domains entries must be valid domain names`
|
|
627
|
-
);
|
|
628
|
-
}
|
|
629
|
-
return domain;
|
|
630
|
-
}
|
|
631
|
-
function parseStringMap(data, errorLabel, options = {}) {
|
|
632
|
-
if (data === void 0) {
|
|
633
|
-
return void 0;
|
|
634
|
-
}
|
|
635
|
-
const record = toRecord(
|
|
636
|
-
data,
|
|
637
|
-
`${errorLabel} must be an object when provided`
|
|
638
|
-
);
|
|
639
|
-
const entries = Object.entries(record);
|
|
640
|
-
if (entries.length === 0) {
|
|
641
|
-
return void 0;
|
|
642
|
-
}
|
|
643
|
-
const result = {};
|
|
644
|
-
const seen = /* @__PURE__ */ new Set();
|
|
645
|
-
for (const [rawKey, rawValue] of entries) {
|
|
646
|
-
const key = rawKey.trim();
|
|
647
|
-
if (!key) {
|
|
648
|
-
throw new Error(`${errorLabel} keys must be non-empty strings`);
|
|
649
|
-
}
|
|
650
|
-
if (typeof rawValue !== "string" || !rawValue.trim()) {
|
|
651
|
-
throw new Error(`${errorLabel}.${key} must be a non-empty string`);
|
|
652
|
-
}
|
|
653
|
-
const normalizedKey = key.toLowerCase();
|
|
654
|
-
if (options.reservedKeys?.has(normalizedKey)) {
|
|
655
|
-
throw new Error(`${errorLabel}.${key} is reserved by the runtime`);
|
|
656
|
-
}
|
|
657
|
-
if (options.forbiddenKeys?.has(normalizedKey)) {
|
|
658
|
-
throw new Error(`${errorLabel}.${key} is not allowed`);
|
|
659
|
-
}
|
|
660
|
-
if (seen.has(normalizedKey)) {
|
|
661
|
-
throw new Error(`${errorLabel}.${key} is duplicated`);
|
|
662
|
-
}
|
|
663
|
-
seen.add(normalizedKey);
|
|
664
|
-
result[key] = rawValue.trim();
|
|
665
|
-
}
|
|
666
|
-
return Object.keys(result).length > 0 ? result : void 0;
|
|
667
|
-
}
|
|
668
|
-
function parseBaseCredentialFields(data, name) {
|
|
669
|
-
const rawDomains = data["api-domains"];
|
|
670
|
-
if (!Array.isArray(rawDomains) || rawDomains.length === 0) {
|
|
671
|
-
throw new Error(
|
|
672
|
-
`Plugin ${name} credentials.api-domains must be a non-empty array of strings`
|
|
673
|
-
);
|
|
674
|
-
}
|
|
675
|
-
const apiDomains = rawDomains.map(
|
|
676
|
-
(rawDomain) => normalizeApiDomain(rawDomain, name)
|
|
677
|
-
);
|
|
678
|
-
const apiHeaders = parseStringMap(
|
|
679
|
-
data["api-headers"],
|
|
680
|
-
`Plugin ${name} credentials.api-headers`,
|
|
681
|
-
{ forbiddenKeys: FORBIDDEN_API_HEADER_NAMES }
|
|
682
|
-
);
|
|
683
|
-
const authTokenEnv = requireEnvVarField(data, "auth-token-env", name);
|
|
684
|
-
const authTokenPlaceholderRaw = data["auth-token-placeholder"];
|
|
685
|
-
if (authTokenPlaceholderRaw !== void 0 && (typeof authTokenPlaceholderRaw !== "string" || !authTokenPlaceholderRaw.trim())) {
|
|
686
|
-
throw new Error(
|
|
687
|
-
`Plugin ${name} credentials.auth-token-placeholder must be a non-empty string when provided`
|
|
688
|
-
);
|
|
689
|
-
}
|
|
690
|
-
return {
|
|
691
|
-
apiDomains,
|
|
692
|
-
...apiHeaders ? { apiHeaders } : {},
|
|
693
|
-
authTokenEnv,
|
|
694
|
-
...typeof authTokenPlaceholderRaw === "string" ? { authTokenPlaceholder: authTokenPlaceholderRaw.trim() } : {}
|
|
695
|
-
};
|
|
696
|
-
}
|
|
697
|
-
function parseCredentials(data, name) {
|
|
698
|
-
const type = data.type;
|
|
699
|
-
if (type === "oauth-bearer") {
|
|
700
|
-
const base = parseBaseCredentialFields(data, name);
|
|
701
|
-
return { type: "oauth-bearer", ...base };
|
|
702
|
-
}
|
|
703
|
-
if (type === "github-app") {
|
|
704
|
-
const base = parseBaseCredentialFields(data, name);
|
|
705
|
-
const appIdEnv = requireEnvVarField(data, "app-id-env", name);
|
|
706
|
-
const privateKeyEnv = requireEnvVarField(data, "private-key-env", name);
|
|
707
|
-
const installationIdEnv = requireEnvVarField(
|
|
708
|
-
data,
|
|
709
|
-
"installation-id-env",
|
|
710
|
-
name
|
|
711
|
-
);
|
|
712
|
-
return {
|
|
713
|
-
type: "github-app",
|
|
714
|
-
...base,
|
|
715
|
-
appIdEnv,
|
|
716
|
-
privateKeyEnv,
|
|
717
|
-
installationIdEnv
|
|
718
|
-
};
|
|
719
|
-
}
|
|
720
|
-
throw new Error(`Plugin ${name} has unsupported credentials.type: "${type}"`);
|
|
721
|
-
}
|
|
722
|
-
function parseRuntimeDependencies(data, name) {
|
|
723
|
-
if (data === void 0) {
|
|
724
|
-
return void 0;
|
|
725
|
-
}
|
|
726
|
-
if (!Array.isArray(data)) {
|
|
727
|
-
throw new Error(`Plugin ${name} runtime-dependencies must be an array`);
|
|
728
|
-
}
|
|
729
|
-
const parsed = [];
|
|
730
|
-
const seen = /* @__PURE__ */ new Set();
|
|
731
|
-
for (const entry of data) {
|
|
732
|
-
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
733
|
-
throw new Error(
|
|
734
|
-
`Plugin ${name} runtime-dependencies entries must be objects`
|
|
735
|
-
);
|
|
736
|
-
}
|
|
737
|
-
const record = entry;
|
|
738
|
-
const type = record.type;
|
|
739
|
-
const packageName = record.package;
|
|
740
|
-
const packageUrl = record.url;
|
|
741
|
-
const version = record.version;
|
|
742
|
-
const sha256 = record.sha256;
|
|
743
|
-
if (typeof type !== "string" || type !== "npm" && type !== "system") {
|
|
744
|
-
throw new Error(
|
|
745
|
-
`Plugin ${name} runtime dependency type must be "npm" or "system"`
|
|
746
|
-
);
|
|
747
|
-
}
|
|
748
|
-
const normalizedPackage = typeof packageName === "string" ? packageName.trim() : "";
|
|
749
|
-
const normalizedUrl = typeof packageUrl === "string" ? packageUrl.trim() : "";
|
|
750
|
-
if (type === "npm") {
|
|
751
|
-
if (!normalizedPackage) {
|
|
752
|
-
throw new Error(
|
|
753
|
-
`Plugin ${name} runtime dependency package must be a non-empty string`
|
|
754
|
-
);
|
|
755
|
-
}
|
|
756
|
-
if (packageUrl !== void 0 || sha256 !== void 0) {
|
|
757
|
-
throw new Error(
|
|
758
|
-
`Plugin ${name} npm runtime dependencies must only include package/version fields`
|
|
759
|
-
);
|
|
760
|
-
}
|
|
761
|
-
const normalizedVersion = typeof version === "string" ? version.trim() : "latest";
|
|
762
|
-
if (!normalizedVersion) {
|
|
763
|
-
throw new Error(
|
|
764
|
-
`Plugin ${name} runtime dependency version must be a non-empty string when provided`
|
|
765
|
-
);
|
|
766
|
-
}
|
|
767
|
-
const dedupeKey2 = `${type}:${normalizedPackage}:${normalizedVersion}`;
|
|
768
|
-
if (seen.has(dedupeKey2)) {
|
|
769
|
-
continue;
|
|
770
|
-
}
|
|
771
|
-
seen.add(dedupeKey2);
|
|
772
|
-
parsed.push({
|
|
773
|
-
type: "npm",
|
|
774
|
-
package: normalizedPackage,
|
|
775
|
-
version: normalizedVersion
|
|
776
|
-
});
|
|
777
|
-
continue;
|
|
778
|
-
}
|
|
779
|
-
if (version !== void 0) {
|
|
780
|
-
throw new Error(
|
|
781
|
-
`Plugin ${name} system runtime dependencies must not include a version`
|
|
782
|
-
);
|
|
783
|
-
}
|
|
784
|
-
if (normalizedPackage && normalizedUrl) {
|
|
785
|
-
throw new Error(
|
|
786
|
-
`Plugin ${name} system runtime dependencies must specify either package or url, not both`
|
|
787
|
-
);
|
|
788
|
-
}
|
|
789
|
-
if (!normalizedPackage && !normalizedUrl) {
|
|
790
|
-
throw new Error(
|
|
791
|
-
`Plugin ${name} system runtime dependencies must specify package or url`
|
|
792
|
-
);
|
|
793
|
-
}
|
|
794
|
-
if (normalizedPackage) {
|
|
795
|
-
if (sha256 !== void 0) {
|
|
796
|
-
throw new Error(
|
|
797
|
-
`Plugin ${name} system runtime dependency package entries must not include sha256`
|
|
798
|
-
);
|
|
799
|
-
}
|
|
800
|
-
const dedupeKey2 = `${type}:package:${normalizedPackage}`;
|
|
801
|
-
if (seen.has(dedupeKey2)) {
|
|
802
|
-
continue;
|
|
803
|
-
}
|
|
804
|
-
seen.add(dedupeKey2);
|
|
805
|
-
parsed.push({
|
|
806
|
-
type: "system",
|
|
807
|
-
package: normalizedPackage
|
|
808
|
-
});
|
|
809
|
-
continue;
|
|
810
|
-
}
|
|
811
|
-
if (!/^https:\/\//i.test(normalizedUrl)) {
|
|
812
|
-
throw new Error(
|
|
813
|
-
`Plugin ${name} system runtime dependency url must be an https URL`
|
|
814
|
-
);
|
|
815
|
-
}
|
|
816
|
-
const normalizedSha256 = typeof sha256 === "string" ? sha256.trim().toLowerCase() : "";
|
|
817
|
-
if (!/^[a-f0-9]{64}$/.test(normalizedSha256)) {
|
|
818
|
-
throw new Error(
|
|
819
|
-
`Plugin ${name} system runtime dependency url entries must include a valid sha256`
|
|
820
|
-
);
|
|
821
|
-
}
|
|
822
|
-
const dedupeKey = `${type}:url:${normalizedUrl}:${normalizedSha256}`;
|
|
823
|
-
if (seen.has(dedupeKey)) {
|
|
824
|
-
continue;
|
|
825
|
-
}
|
|
826
|
-
seen.add(dedupeKey);
|
|
827
|
-
parsed.push({
|
|
828
|
-
type: "system",
|
|
829
|
-
url: normalizedUrl,
|
|
830
|
-
sha256: normalizedSha256
|
|
831
|
-
});
|
|
832
|
-
}
|
|
833
|
-
return parsed.length > 0 ? parsed : void 0;
|
|
834
|
-
}
|
|
835
|
-
function parseRuntimePostinstall(data, name) {
|
|
836
|
-
if (data === void 0) {
|
|
837
|
-
return void 0;
|
|
838
|
-
}
|
|
839
|
-
if (!Array.isArray(data)) {
|
|
840
|
-
throw new Error(`Plugin ${name} runtime-postinstall must be an array`);
|
|
841
|
-
}
|
|
842
|
-
const parsed = [];
|
|
843
|
-
for (const entry of data) {
|
|
844
|
-
if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
|
|
845
|
-
throw new Error(
|
|
846
|
-
`Plugin ${name} runtime-postinstall entries must be objects`
|
|
847
|
-
);
|
|
848
|
-
}
|
|
849
|
-
const record = entry;
|
|
850
|
-
const cmd = typeof record.cmd === "string" ? record.cmd.trim() : "";
|
|
851
|
-
if (!cmd) {
|
|
852
|
-
throw new Error(
|
|
853
|
-
`Plugin ${name} runtime-postinstall cmd must be a non-empty string`
|
|
854
|
-
);
|
|
855
|
-
}
|
|
856
|
-
if (!RUNTIME_POSTINSTALL_CMD_RE.test(cmd)) {
|
|
857
|
-
throw new Error(
|
|
858
|
-
`Plugin ${name} runtime-postinstall cmd must be a single executable token (letters, digits, ., _, /, -)`
|
|
859
|
-
);
|
|
860
|
-
}
|
|
861
|
-
const argsRaw = record.args;
|
|
862
|
-
if (argsRaw !== void 0 && (!Array.isArray(argsRaw) || !argsRaw.every((arg) => typeof arg === "string"))) {
|
|
863
|
-
throw new Error(
|
|
864
|
-
`Plugin ${name} runtime-postinstall args must be an array of strings when provided`
|
|
865
|
-
);
|
|
866
|
-
}
|
|
867
|
-
const sudoRaw = record.sudo;
|
|
868
|
-
if (sudoRaw !== void 0 && typeof sudoRaw !== "boolean") {
|
|
869
|
-
throw new Error(
|
|
870
|
-
`Plugin ${name} runtime-postinstall sudo must be a boolean when provided`
|
|
871
|
-
);
|
|
872
|
-
}
|
|
873
|
-
const normalizedArgs = Array.isArray(argsRaw) ? argsRaw.map((arg) => arg.trim()).filter((arg) => arg.length > 0) : void 0;
|
|
874
|
-
parsed.push({
|
|
875
|
-
cmd,
|
|
876
|
-
...normalizedArgs && normalizedArgs.length > 0 ? { args: normalizedArgs } : {},
|
|
877
|
-
...typeof sudoRaw === "boolean" ? { sudo: sudoRaw } : {}
|
|
878
|
-
});
|
|
879
|
-
}
|
|
880
|
-
return parsed.length > 0 ? parsed : void 0;
|
|
881
|
-
}
|
|
882
|
-
function parseManifest(raw, dir) {
|
|
883
|
-
const data = toRecord(
|
|
884
|
-
parseYaml(raw),
|
|
885
|
-
`Invalid plugin manifest in ${dir}: expected an object`
|
|
886
|
-
);
|
|
887
|
-
const rawName = data.name;
|
|
888
|
-
if (typeof rawName !== "string" || !PLUGIN_NAME_RE.test(rawName)) {
|
|
889
|
-
throw new Error(`Invalid plugin name in ${dir}: "${rawName}"`);
|
|
890
|
-
}
|
|
891
|
-
const name = rawName;
|
|
892
|
-
const rawDescription = data.description;
|
|
893
|
-
if (typeof rawDescription !== "string" || !rawDescription.trim()) {
|
|
894
|
-
throw new Error(`Invalid plugin description in ${dir}`);
|
|
895
|
-
}
|
|
896
|
-
const description = rawDescription;
|
|
897
|
-
const rawCapabilities = data.capabilities;
|
|
898
|
-
if (rawCapabilities !== void 0 && !Array.isArray(rawCapabilities)) {
|
|
899
|
-
throw new Error(
|
|
900
|
-
`Plugin ${name} capabilities must be an array when provided`
|
|
901
|
-
);
|
|
902
|
-
}
|
|
903
|
-
const capabilities = [];
|
|
904
|
-
for (const cap of rawCapabilities ?? []) {
|
|
905
|
-
if (typeof cap !== "string" || !SHORT_CAPABILITY_RE.test(cap)) {
|
|
906
|
-
throw new Error(`Invalid capability token "${cap}" in plugin ${name}`);
|
|
907
|
-
}
|
|
908
|
-
capabilities.push(`${name}.${cap}`);
|
|
909
|
-
}
|
|
910
|
-
const rawConfigKeys = data["config-keys"];
|
|
911
|
-
if (rawConfigKeys !== void 0 && !Array.isArray(rawConfigKeys)) {
|
|
912
|
-
throw new Error(
|
|
913
|
-
`Plugin ${name} config-keys must be an array when provided`
|
|
914
|
-
);
|
|
915
|
-
}
|
|
916
|
-
const configKeys = [];
|
|
917
|
-
for (const key of rawConfigKeys ?? []) {
|
|
918
|
-
if (typeof key !== "string" || !SHORT_CONFIG_KEY_RE.test(key)) {
|
|
919
|
-
throw new Error(`Invalid config key "${key}" in plugin ${name}`);
|
|
920
|
-
}
|
|
921
|
-
configKeys.push(`${name}.${key}`);
|
|
922
|
-
}
|
|
923
|
-
const credentialsRaw = data.credentials;
|
|
924
|
-
if (credentialsRaw !== void 0) {
|
|
925
|
-
toRecord(
|
|
926
|
-
credentialsRaw,
|
|
927
|
-
`Plugin ${name} credentials must be an object when provided`
|
|
928
|
-
);
|
|
929
|
-
}
|
|
930
|
-
const credentials = credentialsRaw ? parseCredentials(credentialsRaw, name) : void 0;
|
|
931
|
-
const runtimeDependencies = parseRuntimeDependencies(
|
|
932
|
-
data["runtime-dependencies"],
|
|
933
|
-
name
|
|
934
|
-
);
|
|
935
|
-
const runtimePostinstall = parseRuntimePostinstall(
|
|
936
|
-
data["runtime-postinstall"],
|
|
937
|
-
name
|
|
938
|
-
);
|
|
939
|
-
const manifest = {
|
|
940
|
-
name,
|
|
941
|
-
description,
|
|
942
|
-
capabilities,
|
|
943
|
-
configKeys,
|
|
944
|
-
...credentials ? { credentials } : {},
|
|
945
|
-
...runtimeDependencies ? { runtimeDependencies } : {},
|
|
946
|
-
...runtimePostinstall ? { runtimePostinstall } : {}
|
|
947
|
-
};
|
|
948
|
-
const oauthRaw = data.oauth ? toRecord(data.oauth, `Plugin ${name} oauth must be an object`) : void 0;
|
|
949
|
-
if (oauthRaw) {
|
|
950
|
-
if (!credentials) {
|
|
951
|
-
throw new Error(`Plugin ${name} oauth requires credentials`);
|
|
952
|
-
}
|
|
953
|
-
if (credentials.type !== "oauth-bearer") {
|
|
954
|
-
throw new Error(
|
|
955
|
-
`Plugin ${name} oauth requires credentials.type "oauth-bearer"`
|
|
956
|
-
);
|
|
957
|
-
}
|
|
958
|
-
const authorizeParams = parseStringMap(
|
|
959
|
-
oauthRaw["authorize-params"],
|
|
960
|
-
`Plugin ${name} oauth.authorize-params`,
|
|
961
|
-
{ reservedKeys: RESERVED_AUTHORIZE_PARAM_KEYS }
|
|
962
|
-
);
|
|
963
|
-
const tokenExtraHeaders = parseStringMap(
|
|
964
|
-
oauthRaw["token-extra-headers"],
|
|
965
|
-
`Plugin ${name} oauth.token-extra-headers`,
|
|
966
|
-
{ forbiddenKeys: FORBIDDEN_TOKEN_HEADER_NAMES }
|
|
967
|
-
);
|
|
968
|
-
const tokenAuthMethodRaw = oauthRaw["token-auth-method"];
|
|
969
|
-
let tokenAuthMethod;
|
|
970
|
-
if (tokenAuthMethodRaw !== void 0) {
|
|
971
|
-
const parsedTokenAuthMethod = requireStringField(
|
|
972
|
-
oauthRaw,
|
|
973
|
-
"token-auth-method",
|
|
974
|
-
`Plugin ${name} oauth.token-auth-method must be a non-empty string`
|
|
975
|
-
);
|
|
976
|
-
if (parsedTokenAuthMethod !== "body" && parsedTokenAuthMethod !== "basic") {
|
|
977
|
-
throw new Error(
|
|
978
|
-
`Plugin ${name} oauth.token-auth-method must be "body" or "basic"`
|
|
979
|
-
);
|
|
980
|
-
}
|
|
981
|
-
tokenAuthMethod = parsedTokenAuthMethod;
|
|
982
|
-
}
|
|
983
|
-
manifest.oauth = {
|
|
984
|
-
clientIdEnv: requireEnvVarField(oauthRaw, "client-id-env", name),
|
|
985
|
-
clientSecretEnv: requireEnvVarField(oauthRaw, "client-secret-env", name),
|
|
986
|
-
authorizeEndpoint: requireHttpsUrlField(
|
|
987
|
-
oauthRaw,
|
|
988
|
-
"authorize-endpoint",
|
|
989
|
-
name
|
|
990
|
-
),
|
|
991
|
-
tokenEndpoint: requireHttpsUrlField(oauthRaw, "token-endpoint", name),
|
|
992
|
-
...oauthRaw.scope !== void 0 ? {
|
|
993
|
-
scope: requireStringField(
|
|
994
|
-
oauthRaw,
|
|
995
|
-
"scope",
|
|
996
|
-
`Plugin ${name} oauth.scope must be a non-empty string`
|
|
997
|
-
)
|
|
998
|
-
} : {},
|
|
999
|
-
...authorizeParams ? { authorizeParams } : {},
|
|
1000
|
-
...tokenAuthMethod ? { tokenAuthMethod } : {},
|
|
1001
|
-
...tokenExtraHeaders ? { tokenExtraHeaders } : {}
|
|
1002
|
-
};
|
|
1003
|
-
}
|
|
1004
|
-
const targetRaw = data.target ? toRecord(data.target, `Plugin ${name} target must be an object`) : void 0;
|
|
1005
|
-
if (targetRaw) {
|
|
1006
|
-
if (targetRaw.type !== "repo") {
|
|
1007
|
-
throw new Error(`Plugin ${name} target.type must be "repo"`);
|
|
1008
|
-
}
|
|
1009
|
-
const rawConfigKey = targetRaw["config-key"];
|
|
1010
|
-
if (typeof rawConfigKey !== "string" || !rawConfigKey.trim()) {
|
|
1011
|
-
throw new Error(
|
|
1012
|
-
`Plugin ${name} target.config-key must be a non-empty string`
|
|
1013
|
-
);
|
|
1014
|
-
}
|
|
1015
|
-
if (!SHORT_CONFIG_KEY_RE.test(rawConfigKey)) {
|
|
1016
|
-
throw new Error(
|
|
1017
|
-
`Plugin ${name} target.config-key "${rawConfigKey}" is invalid`
|
|
1018
|
-
);
|
|
1019
|
-
}
|
|
1020
|
-
const qualifiedKey = `${name}.${rawConfigKey}`;
|
|
1021
|
-
if (!configKeys.includes(qualifiedKey)) {
|
|
1022
|
-
throw new Error(
|
|
1023
|
-
`Plugin ${name} target.config-key "${rawConfigKey}" must be listed in config-keys`
|
|
1024
|
-
);
|
|
1025
|
-
}
|
|
1026
|
-
manifest.target = { type: "repo", configKey: qualifiedKey };
|
|
1027
|
-
}
|
|
1028
|
-
return manifest;
|
|
1029
|
-
}
|
|
1030
565
|
var pluginDefinitions = [];
|
|
1031
566
|
var capabilityToPlugin = /* @__PURE__ */ new Map();
|
|
1032
567
|
var pluginConfigKeys = /* @__PURE__ */ new Set();
|
|
@@ -1034,7 +569,7 @@ var pluginsByName = /* @__PURE__ */ new Map();
|
|
|
1034
569
|
var packageSkillRoots = /* @__PURE__ */ new Set();
|
|
1035
570
|
var pluginsLoaded = false;
|
|
1036
571
|
function registerPluginManifest(raw, pluginDir) {
|
|
1037
|
-
const manifest =
|
|
572
|
+
const manifest = parsePluginManifest(raw, pluginDir);
|
|
1038
573
|
if (pluginsByName.has(manifest.name)) {
|
|
1039
574
|
return;
|
|
1040
575
|
}
|
|
@@ -1400,6 +935,7 @@ function createQueuedStateAdapter(base) {
|
|
|
1400
935
|
return lock;
|
|
1401
936
|
};
|
|
1402
937
|
return {
|
|
938
|
+
appendToList: (key, value, options) => base.appendToList(key, value, options),
|
|
1403
939
|
connect: () => base.connect(),
|
|
1404
940
|
disconnect: () => base.disconnect(),
|
|
1405
941
|
subscribe: (threadId) => base.subscribe(threadId),
|
|
@@ -1408,7 +944,9 @@ function createQueuedStateAdapter(base) {
|
|
|
1408
944
|
acquireLock,
|
|
1409
945
|
releaseLock: (lock) => base.releaseLock(lock),
|
|
1410
946
|
extendLock: (lock, ttlMs) => base.extendLock(lock, Math.max(ttlMs, MIN_LOCK_TTL_MS)),
|
|
947
|
+
forceReleaseLock: (threadId) => base.forceReleaseLock(threadId),
|
|
1411
948
|
get: (key) => base.get(key),
|
|
949
|
+
getList: (key) => base.getList(key),
|
|
1412
950
|
set: (key, value, ttlMs) => base.set(key, value, ttlMs),
|
|
1413
951
|
setIfNotExists: (key, value, ttlMs) => base.setIfNotExists(key, value, ttlMs),
|
|
1414
952
|
delete: (key) => base.delete(key)
|
|
@@ -1553,7 +1091,11 @@ async function acquireQueueMessageProcessingOwnership(args) {
|
|
|
1553
1091
|
});
|
|
1554
1092
|
const result = await getRedisStateAdapter().getClient().eval(CLAIM_OR_RECLAIM_PROCESSING_SCRIPT, {
|
|
1555
1093
|
keys: [key],
|
|
1556
|
-
arguments: [
|
|
1094
|
+
arguments: [
|
|
1095
|
+
String(nowMs),
|
|
1096
|
+
String(QUEUE_MESSAGE_PROCESSING_TTL_MS),
|
|
1097
|
+
payload
|
|
1098
|
+
]
|
|
1557
1099
|
});
|
|
1558
1100
|
if (result === 1) {
|
|
1559
1101
|
return "acquired";
|
|
@@ -1577,7 +1119,11 @@ async function refreshQueueMessageProcessingOwnership(args) {
|
|
|
1577
1119
|
});
|
|
1578
1120
|
const result = await getRedisStateAdapter().getClient().eval(UPDATE_PROCESSING_STATE_IF_OWNER_SCRIPT, {
|
|
1579
1121
|
keys: [queueMessageKey(args.rawKey)],
|
|
1580
|
-
arguments: [
|
|
1122
|
+
arguments: [
|
|
1123
|
+
args.ownerToken,
|
|
1124
|
+
String(QUEUE_MESSAGE_PROCESSING_TTL_MS),
|
|
1125
|
+
payload
|
|
1126
|
+
]
|
|
1581
1127
|
});
|
|
1582
1128
|
return result === 1;
|
|
1583
1129
|
}
|
|
@@ -1591,7 +1137,11 @@ async function completeQueueMessageProcessingOwnership(args) {
|
|
|
1591
1137
|
});
|
|
1592
1138
|
const result = await getRedisStateAdapter().getClient().eval(UPDATE_PROCESSING_STATE_IF_OWNER_SCRIPT, {
|
|
1593
1139
|
keys: [queueMessageKey(args.rawKey)],
|
|
1594
|
-
arguments: [
|
|
1140
|
+
arguments: [
|
|
1141
|
+
args.ownerToken,
|
|
1142
|
+
String(QUEUE_MESSAGE_COMPLETED_TTL_MS),
|
|
1143
|
+
payload
|
|
1144
|
+
]
|
|
1595
1145
|
});
|
|
1596
1146
|
return result === 1;
|
|
1597
1147
|
}
|
|
@@ -1606,18 +1156,27 @@ async function failQueueMessageProcessingOwnership(args) {
|
|
|
1606
1156
|
});
|
|
1607
1157
|
const result = await getRedisStateAdapter().getClient().eval(UPDATE_PROCESSING_STATE_IF_OWNER_SCRIPT, {
|
|
1608
1158
|
keys: [queueMessageKey(args.rawKey)],
|
|
1609
|
-
arguments: [
|
|
1159
|
+
arguments: [
|
|
1160
|
+
args.ownerToken,
|
|
1161
|
+
String(QUEUE_MESSAGE_FAILED_TTL_MS),
|
|
1162
|
+
payload
|
|
1163
|
+
]
|
|
1610
1164
|
});
|
|
1611
1165
|
return result === 1;
|
|
1612
1166
|
}
|
|
1613
1167
|
async function getAgentTurnSessionCheckpoint(conversationId, sessionId) {
|
|
1614
1168
|
await getStateAdapter().connect();
|
|
1615
|
-
const value = await getStateAdapter().get(
|
|
1169
|
+
const value = await getStateAdapter().get(
|
|
1170
|
+
agentTurnSessionKey(conversationId, sessionId)
|
|
1171
|
+
);
|
|
1616
1172
|
return parseAgentTurnSessionCheckpoint(value);
|
|
1617
1173
|
}
|
|
1618
1174
|
async function upsertAgentTurnSessionCheckpoint(args) {
|
|
1619
1175
|
await getStateAdapter().connect();
|
|
1620
|
-
const existing = await getAgentTurnSessionCheckpoint(
|
|
1176
|
+
const existing = await getAgentTurnSessionCheckpoint(
|
|
1177
|
+
args.conversationId,
|
|
1178
|
+
args.sessionId
|
|
1179
|
+
);
|
|
1621
1180
|
const checkpoint = {
|
|
1622
1181
|
checkpointVersion: (existing?.checkpointVersion ?? 0) + 1,
|
|
1623
1182
|
conversationId: args.conversationId,
|
|
@@ -1630,7 +1189,11 @@ async function upsertAgentTurnSessionCheckpoint(args) {
|
|
|
1630
1189
|
...typeof args.resumedFromSliceId === "number" ? { resumedFromSliceId: args.resumedFromSliceId } : {}
|
|
1631
1190
|
};
|
|
1632
1191
|
const ttlMs = Math.max(1, args.ttlMs ?? AGENT_TURN_SESSION_TTL_MS);
|
|
1633
|
-
await getStateAdapter().set(
|
|
1192
|
+
await getStateAdapter().set(
|
|
1193
|
+
agentTurnSessionKey(args.conversationId, args.sessionId),
|
|
1194
|
+
JSON.stringify(checkpoint),
|
|
1195
|
+
ttlMs
|
|
1196
|
+
);
|
|
1634
1197
|
return checkpoint;
|
|
1635
1198
|
}
|
|
1636
1199
|
|
|
@@ -2196,6 +1759,7 @@ export {
|
|
|
2196
1759
|
homeDir,
|
|
2197
1760
|
skillRoots,
|
|
2198
1761
|
soulPathCandidates,
|
|
1762
|
+
aboutPathCandidates,
|
|
2199
1763
|
resolveAuthTokenPlaceholder,
|
|
2200
1764
|
CredentialUnavailableError,
|
|
2201
1765
|
buildOAuthTokenRequest,
|