@kaddo/mcp 3.82.0 → 3.84.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/index.js +313 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11657,7 +11657,7 @@ function systemImpactCandidatesTool(root, args) {
|
|
|
11657
11657
|
|
|
11658
11658
|
// ../cli/src/services/integrations.ts
|
|
11659
11659
|
import matter13 from "gray-matter";
|
|
11660
|
-
import { parse as parseYaml12 } from "yaml";
|
|
11660
|
+
import { parse as parseYaml12, stringify as stringifyYaml6 } from "yaml";
|
|
11661
11661
|
|
|
11662
11662
|
// ../cli/src/core/work-item-write.ts
|
|
11663
11663
|
import fs5 from "fs";
|
|
@@ -11751,6 +11751,71 @@ function parseCredentials(raw, id, findings) {
|
|
|
11751
11751
|
}
|
|
11752
11752
|
return creds;
|
|
11753
11753
|
}
|
|
11754
|
+
function parseSecrets(raw, id, findings) {
|
|
11755
|
+
const secrets = {};
|
|
11756
|
+
if (raw == null) return secrets;
|
|
11757
|
+
if (typeof raw !== "object" || Array.isArray(raw)) {
|
|
11758
|
+
findings.push({ level: "blocking", id, message: `Integration "${id}": secrets must be a mapping of logical references.` });
|
|
11759
|
+
return secrets;
|
|
11760
|
+
}
|
|
11761
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
11762
|
+
if (typeof value === "string" && value.trim()) {
|
|
11763
|
+
if (value.length > 100 || /^(ghp_|sk-|xox[bpsa]-|glpat-|ey[A-Za-z0-9])/i.test(value)) {
|
|
11764
|
+
findings.push({ level: "blocking", id, message: `Integration "${id}": secret "${key}" appears to contain an actual credential, not a reference name.` });
|
|
11765
|
+
continue;
|
|
11766
|
+
}
|
|
11767
|
+
secrets[key] = value.trim();
|
|
11768
|
+
} else {
|
|
11769
|
+
findings.push({ level: "warning", id, message: `Integration "${id}": ignoring non-string secret entry "${key}".` });
|
|
11770
|
+
}
|
|
11771
|
+
}
|
|
11772
|
+
return secrets;
|
|
11773
|
+
}
|
|
11774
|
+
function toStringArray3(raw) {
|
|
11775
|
+
if (raw == null) return void 0;
|
|
11776
|
+
if (Array.isArray(raw)) return raw.filter((v) => typeof v === "string" && v.trim() !== "").map((v) => v.trim());
|
|
11777
|
+
if (typeof raw === "string" && raw.trim()) return [raw.trim()];
|
|
11778
|
+
return void 0;
|
|
11779
|
+
}
|
|
11780
|
+
function parseFilters(raw) {
|
|
11781
|
+
if (raw == null || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
11782
|
+
const o2 = raw;
|
|
11783
|
+
const filters = {};
|
|
11784
|
+
let hasAny = false;
|
|
11785
|
+
const types = toStringArray3(o2.types);
|
|
11786
|
+
if (types?.length) {
|
|
11787
|
+
filters.types = types;
|
|
11788
|
+
hasAny = true;
|
|
11789
|
+
}
|
|
11790
|
+
const statuses = toStringArray3(o2.statuses);
|
|
11791
|
+
if (statuses?.length) {
|
|
11792
|
+
filters.statuses = statuses;
|
|
11793
|
+
hasAny = true;
|
|
11794
|
+
}
|
|
11795
|
+
const labels = toStringArray3(o2.labels);
|
|
11796
|
+
if (labels?.length) {
|
|
11797
|
+
filters.labels = labels;
|
|
11798
|
+
hasAny = true;
|
|
11799
|
+
}
|
|
11800
|
+
const assignees = toStringArray3(o2.assignees);
|
|
11801
|
+
if (assignees?.length) {
|
|
11802
|
+
filters.assignees = assignees;
|
|
11803
|
+
hasAny = true;
|
|
11804
|
+
}
|
|
11805
|
+
if (typeof o2.updatedAfter === "string" && o2.updatedAfter.trim()) {
|
|
11806
|
+
filters.updatedAfter = o2.updatedAfter.trim();
|
|
11807
|
+
hasAny = true;
|
|
11808
|
+
}
|
|
11809
|
+
if (typeof o2.search === "string" && o2.search.trim()) {
|
|
11810
|
+
filters.search = o2.search.trim();
|
|
11811
|
+
hasAny = true;
|
|
11812
|
+
}
|
|
11813
|
+
if (typeof o2.providerQuery === "string" && o2.providerQuery.trim()) {
|
|
11814
|
+
filters.providerQuery = o2.providerQuery.trim();
|
|
11815
|
+
hasAny = true;
|
|
11816
|
+
}
|
|
11817
|
+
return hasAny ? filters : void 0;
|
|
11818
|
+
}
|
|
11754
11819
|
function parseIntegrationsConfig(raw, opts) {
|
|
11755
11820
|
const findings = [];
|
|
11756
11821
|
const integrations = [];
|
|
@@ -11783,12 +11848,14 @@ function parseIntegrationsConfig(raw, opts) {
|
|
|
11783
11848
|
const enabled = o2.enabled === void 0 ? true : o2.enabled === true || o2.enabled === "true";
|
|
11784
11849
|
const config = o2.config && typeof o2.config === "object" && !Array.isArray(o2.config) ? o2.config : {};
|
|
11785
11850
|
const credentials = parseCredentials(o2.credentials, id, findings);
|
|
11851
|
+
const secrets = parseSecrets(o2.secrets, id, findings);
|
|
11852
|
+
const filters = parseFilters(o2.filters);
|
|
11786
11853
|
const timeoutMs = typeof o2.timeout_ms === "number" ? o2.timeout_ms : typeof o2.timeoutMs === "number" ? o2.timeoutMs : void 0;
|
|
11787
|
-
integrations.push({ id, adapter, enabled, config, credentials, timeoutMs });
|
|
11854
|
+
integrations.push({ id, adapter, enabled, config, credentials, secrets, filters, timeoutMs });
|
|
11788
11855
|
}
|
|
11789
11856
|
return { integrations, findings };
|
|
11790
11857
|
}
|
|
11791
|
-
function
|
|
11858
|
+
async function resolveAllCredentials(integration, resolver, env) {
|
|
11792
11859
|
const credentials = {};
|
|
11793
11860
|
const missing = [];
|
|
11794
11861
|
for (const [name, ref] of Object.entries(integration.credentials)) {
|
|
@@ -11796,8 +11863,104 @@ function resolveCredentials(integration, env) {
|
|
|
11796
11863
|
if (value && value.length > 0) credentials[name] = value;
|
|
11797
11864
|
else missing.push(ref.env);
|
|
11798
11865
|
}
|
|
11866
|
+
for (const [name, ref] of Object.entries(integration.secrets)) {
|
|
11867
|
+
if (credentials[name]) continue;
|
|
11868
|
+
const value = await resolver.resolve(ref);
|
|
11869
|
+
if (value !== void 0) credentials[name] = value;
|
|
11870
|
+
else missing.push(ref);
|
|
11871
|
+
}
|
|
11799
11872
|
return { credentials, missing };
|
|
11800
11873
|
}
|
|
11874
|
+
function mergeFilters(base, overlay) {
|
|
11875
|
+
if (!base && !overlay) return {};
|
|
11876
|
+
if (!base) return { ...overlay };
|
|
11877
|
+
if (!overlay) return { ...base };
|
|
11878
|
+
return {
|
|
11879
|
+
types: overlay.types?.length ? overlay.types : base.types,
|
|
11880
|
+
statuses: overlay.statuses?.length ? overlay.statuses : base.statuses,
|
|
11881
|
+
labels: overlay.labels?.length ? overlay.labels : base.labels,
|
|
11882
|
+
assignees: overlay.assignees?.length ? overlay.assignees : base.assignees,
|
|
11883
|
+
updatedAfter: overlay.updatedAfter ?? base.updatedAfter,
|
|
11884
|
+
search: overlay.search ?? base.search,
|
|
11885
|
+
providerQuery: overlay.providerQuery ?? base.providerQuery
|
|
11886
|
+
};
|
|
11887
|
+
}
|
|
11888
|
+
|
|
11889
|
+
// ../integrations/src/secrets.ts
|
|
11890
|
+
import { readFileSync as readFileSync2, writeFileSync, mkdirSync, existsSync as existsSync2, unlinkSync } from "fs";
|
|
11891
|
+
import { dirname as dirname2 } from "path";
|
|
11892
|
+
var SECRETS_FILENAME = ".secrets.json";
|
|
11893
|
+
function secretsPath(projectDir) {
|
|
11894
|
+
return `${projectDir}/.kaddo/${SECRETS_FILENAME}`;
|
|
11895
|
+
}
|
|
11896
|
+
function loadStore(filePath) {
|
|
11897
|
+
if (!existsSync2(filePath)) return {};
|
|
11898
|
+
try {
|
|
11899
|
+
const raw = readFileSync2(filePath, "utf-8");
|
|
11900
|
+
const parsed = JSON.parse(raw);
|
|
11901
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
|
|
11902
|
+
return {};
|
|
11903
|
+
} catch {
|
|
11904
|
+
return {};
|
|
11905
|
+
}
|
|
11906
|
+
}
|
|
11907
|
+
function saveStore(filePath, store) {
|
|
11908
|
+
mkdirSync(dirname2(filePath), { recursive: true });
|
|
11909
|
+
writeFileSync(filePath, JSON.stringify(store, null, 2) + "\n", "utf-8");
|
|
11910
|
+
}
|
|
11911
|
+
function createLocalSecretProvider(projectDir) {
|
|
11912
|
+
const fp = secretsPath(projectDir);
|
|
11913
|
+
return {
|
|
11914
|
+
async get(key) {
|
|
11915
|
+
const store = loadStore(fp);
|
|
11916
|
+
const val = store[key];
|
|
11917
|
+
return val !== void 0 && val !== "" ? val : void 0;
|
|
11918
|
+
},
|
|
11919
|
+
async set(key, value) {
|
|
11920
|
+
const store = loadStore(fp);
|
|
11921
|
+
store[key] = value;
|
|
11922
|
+
saveStore(fp, store);
|
|
11923
|
+
},
|
|
11924
|
+
async delete(key) {
|
|
11925
|
+
const store = loadStore(fp);
|
|
11926
|
+
delete store[key];
|
|
11927
|
+
saveStore(fp, store);
|
|
11928
|
+
},
|
|
11929
|
+
async exists(key) {
|
|
11930
|
+
const store = loadStore(fp);
|
|
11931
|
+
return key in store && store[key] !== void 0 && store[key] !== "";
|
|
11932
|
+
}
|
|
11933
|
+
};
|
|
11934
|
+
}
|
|
11935
|
+
function createEnvSecretProvider(env = process.env) {
|
|
11936
|
+
return {
|
|
11937
|
+
async get(key) {
|
|
11938
|
+
const val = env[key];
|
|
11939
|
+
return val !== void 0 && val !== "" ? val : void 0;
|
|
11940
|
+
},
|
|
11941
|
+
async set() {
|
|
11942
|
+
throw new Error("Environment secret provider is read-only.");
|
|
11943
|
+
},
|
|
11944
|
+
async delete() {
|
|
11945
|
+
throw new Error("Environment secret provider is read-only.");
|
|
11946
|
+
},
|
|
11947
|
+
async exists(key) {
|
|
11948
|
+
const val = env[key];
|
|
11949
|
+
return val !== void 0 && val !== "";
|
|
11950
|
+
}
|
|
11951
|
+
};
|
|
11952
|
+
}
|
|
11953
|
+
function createCompositeResolver(...providers) {
|
|
11954
|
+
return {
|
|
11955
|
+
async resolve(reference) {
|
|
11956
|
+
for (const provider of providers) {
|
|
11957
|
+
const val = await provider.get(reference);
|
|
11958
|
+
if (val !== void 0) return val;
|
|
11959
|
+
}
|
|
11960
|
+
return void 0;
|
|
11961
|
+
}
|
|
11962
|
+
};
|
|
11963
|
+
}
|
|
11801
11964
|
|
|
11802
11965
|
// ../integrations/src/registry.ts
|
|
11803
11966
|
var DuplicateAdapterError = class extends Error {
|
|
@@ -11838,6 +12001,7 @@ var DEFAULT_ITEMS = [
|
|
|
11838
12001
|
status: "Open",
|
|
11839
12002
|
url: "https://example.test/mock/EXT-001",
|
|
11840
12003
|
labels: ["registration", "beta"],
|
|
12004
|
+
assignees: [{ name: "Alice" }],
|
|
11841
12005
|
createdAt: "2026-01-05T10:00:00.000Z",
|
|
11842
12006
|
updatedAt: "2026-02-01T09:30:00.000Z",
|
|
11843
12007
|
rawMetadata: { board: "delivery" }
|
|
@@ -11851,8 +12015,86 @@ var DEFAULT_ITEMS = [
|
|
|
11851
12015
|
status: "To Do",
|
|
11852
12016
|
url: "https://example.test/mock/EXT-002",
|
|
11853
12017
|
labels: ["onboarding"],
|
|
12018
|
+
assignees: [{ name: "Bob" }],
|
|
11854
12019
|
createdAt: "2026-01-08T12:00:00.000Z",
|
|
11855
12020
|
updatedAt: "2026-01-20T15:00:00.000Z"
|
|
12021
|
+
},
|
|
12022
|
+
{
|
|
12023
|
+
externalId: "EXT-003",
|
|
12024
|
+
provider: MOCK_ADAPTER_ID,
|
|
12025
|
+
title: "Fix authentication error on mobile",
|
|
12026
|
+
description: "Users on iOS 17 see a blank screen after OAuth redirect.",
|
|
12027
|
+
type: "Bug",
|
|
12028
|
+
status: "In Progress",
|
|
12029
|
+
url: "https://example.test/mock/EXT-003",
|
|
12030
|
+
labels: ["auth", "mobile", "critical"],
|
|
12031
|
+
assignees: [{ name: "Alice" }],
|
|
12032
|
+
createdAt: "2026-02-10T08:00:00.000Z",
|
|
12033
|
+
updatedAt: "2026-03-01T14:00:00.000Z"
|
|
12034
|
+
},
|
|
12035
|
+
{
|
|
12036
|
+
externalId: "EXT-004",
|
|
12037
|
+
provider: MOCK_ADAPTER_ID,
|
|
12038
|
+
title: "Design system token audit",
|
|
12039
|
+
description: "Review and consolidate design tokens across the component library.",
|
|
12040
|
+
type: "Task",
|
|
12041
|
+
status: "To Do",
|
|
12042
|
+
url: "https://example.test/mock/EXT-004",
|
|
12043
|
+
labels: ["frontend", "design-system"],
|
|
12044
|
+
createdAt: "2026-02-15T10:00:00.000Z",
|
|
12045
|
+
updatedAt: "2026-02-20T11:00:00.000Z"
|
|
12046
|
+
},
|
|
12047
|
+
{
|
|
12048
|
+
externalId: "EXT-005",
|
|
12049
|
+
provider: MOCK_ADAPTER_ID,
|
|
12050
|
+
title: "Migrate billing service to new payment gateway",
|
|
12051
|
+
description: "Stripe v2 migration \u2014 switch from legacy Charges API to Payment Intents.",
|
|
12052
|
+
type: "Epic",
|
|
12053
|
+
status: "Open",
|
|
12054
|
+
url: "https://example.test/mock/EXT-005",
|
|
12055
|
+
labels: ["billing", "backend", "migration"],
|
|
12056
|
+
assignees: [{ name: "Carol" }],
|
|
12057
|
+
createdAt: "2026-01-20T09:00:00.000Z",
|
|
12058
|
+
updatedAt: "2026-03-05T16:00:00.000Z"
|
|
12059
|
+
},
|
|
12060
|
+
{
|
|
12061
|
+
externalId: "EXT-006",
|
|
12062
|
+
provider: MOCK_ADAPTER_ID,
|
|
12063
|
+
title: "Add CSV export to reports",
|
|
12064
|
+
description: "Users need to export analytics reports as CSV for external tools.",
|
|
12065
|
+
type: "Feature",
|
|
12066
|
+
status: "In Progress",
|
|
12067
|
+
url: "https://example.test/mock/EXT-006",
|
|
12068
|
+
labels: ["reports", "backend"],
|
|
12069
|
+
assignees: [{ name: "Bob" }],
|
|
12070
|
+
createdAt: "2026-02-25T13:00:00.000Z",
|
|
12071
|
+
updatedAt: "2026-03-10T10:00:00.000Z"
|
|
12072
|
+
},
|
|
12073
|
+
{
|
|
12074
|
+
externalId: "EXT-007",
|
|
12075
|
+
provider: MOCK_ADAPTER_ID,
|
|
12076
|
+
title: "Improve search relevance scoring",
|
|
12077
|
+
description: "Tweak TF-IDF weights and add trigram matching for better search results.",
|
|
12078
|
+
type: "Task",
|
|
12079
|
+
status: "Done",
|
|
12080
|
+
url: "https://example.test/mock/EXT-007",
|
|
12081
|
+
labels: ["search", "backend"],
|
|
12082
|
+
assignees: [{ name: "Alice" }],
|
|
12083
|
+
createdAt: "2026-01-12T07:00:00.000Z",
|
|
12084
|
+
updatedAt: "2026-02-28T17:00:00.000Z"
|
|
12085
|
+
},
|
|
12086
|
+
{
|
|
12087
|
+
externalId: "EXT-008",
|
|
12088
|
+
provider: MOCK_ADAPTER_ID,
|
|
12089
|
+
title: "Set up E2E test pipeline",
|
|
12090
|
+
description: "Configure Playwright tests running on every PR via GitHub Actions.",
|
|
12091
|
+
type: "Task",
|
|
12092
|
+
status: "Done",
|
|
12093
|
+
url: "https://example.test/mock/EXT-008",
|
|
12094
|
+
labels: ["testing", "ci"],
|
|
12095
|
+
assignees: [{ name: "Carol" }],
|
|
12096
|
+
createdAt: "2026-01-30T11:00:00.000Z",
|
|
12097
|
+
updatedAt: "2026-02-15T09:00:00.000Z"
|
|
11856
12098
|
}
|
|
11857
12099
|
];
|
|
11858
12100
|
function simulationOf(context, fallback) {
|
|
@@ -11883,7 +12125,41 @@ function createMockAdapter(opts = {}) {
|
|
|
11883
12125
|
id: MOCK_ADAPTER_ID,
|
|
11884
12126
|
displayName: "Mock Work Source",
|
|
11885
12127
|
version: "1.0.0",
|
|
11886
|
-
description: "Deterministic offline reference adapter for validating the integration foundation."
|
|
12128
|
+
description: "Deterministic offline reference adapter for validating the integration foundation.",
|
|
12129
|
+
icon: "mock",
|
|
12130
|
+
filterCapabilities: {
|
|
12131
|
+
types: { supported: true, multiple: true },
|
|
12132
|
+
statuses: { supported: true, multiple: true },
|
|
12133
|
+
labels: { supported: true, multiple: true },
|
|
12134
|
+
assignees: { supported: true, multiple: true },
|
|
12135
|
+
updatedAfter: { supported: true },
|
|
12136
|
+
search: { supported: true },
|
|
12137
|
+
providerQuery: { supported: false }
|
|
12138
|
+
},
|
|
12139
|
+
configSchema: {
|
|
12140
|
+
simulate: {
|
|
12141
|
+
type: "select",
|
|
12142
|
+
required: false,
|
|
12143
|
+
label: "Simulation mode",
|
|
12144
|
+
description: "Controls what the mock adapter simulates during verify/read operations.",
|
|
12145
|
+
options: [
|
|
12146
|
+
{ value: "available", label: "Available" },
|
|
12147
|
+
{ value: "unauthorized", label: "Unauthorized" },
|
|
12148
|
+
{ value: "rate-limited", label: "Rate Limited" },
|
|
12149
|
+
{ value: "unavailable", label: "Unavailable" },
|
|
12150
|
+
{ value: "timeout", label: "Timeout" }
|
|
12151
|
+
],
|
|
12152
|
+
defaultValue: "available"
|
|
12153
|
+
}
|
|
12154
|
+
},
|
|
12155
|
+
secretSchema: {
|
|
12156
|
+
token: {
|
|
12157
|
+
type: "string",
|
|
12158
|
+
required: false,
|
|
12159
|
+
label: "API Token",
|
|
12160
|
+
description: "Optional token for testing secret handling (not used by the mock adapter)."
|
|
12161
|
+
}
|
|
12162
|
+
}
|
|
11887
12163
|
},
|
|
11888
12164
|
capabilities: {
|
|
11889
12165
|
workItems: { list: true, read: true, import: true, write: false, statusSync: false, comments: false, webhooks: false }
|
|
@@ -11906,9 +12182,24 @@ function createMockAdapter(opts = {}) {
|
|
|
11906
12182
|
readFailure(simulationOf(request.context, defaultSim));
|
|
11907
12183
|
let pool = items;
|
|
11908
12184
|
const f3 = request.filters;
|
|
11909
|
-
if (f3?.
|
|
11910
|
-
|
|
11911
|
-
|
|
12185
|
+
if (f3?.statuses?.length) {
|
|
12186
|
+
const lower = f3.statuses.map((s) => s.toLowerCase());
|
|
12187
|
+
pool = pool.filter((i) => lower.includes((i.status ?? "").toLowerCase()));
|
|
12188
|
+
}
|
|
12189
|
+
if (f3?.types?.length) {
|
|
12190
|
+
const lower = f3.types.map((t) => t.toLowerCase());
|
|
12191
|
+
pool = pool.filter((i) => lower.includes((i.type ?? "").toLowerCase()));
|
|
12192
|
+
}
|
|
12193
|
+
if (f3?.labels?.length) {
|
|
12194
|
+
const lower = f3.labels.map((l2) => l2.toLowerCase());
|
|
12195
|
+
pool = pool.filter((i) => i.labels?.some((il) => lower.includes(il.toLowerCase())));
|
|
12196
|
+
}
|
|
12197
|
+
if (f3?.assignees?.length) {
|
|
12198
|
+
const lower = f3.assignees.map((a2) => a2.toLowerCase());
|
|
12199
|
+
pool = pool.filter((i) => i.assignees?.some((a2) => lower.includes((a2.name ?? "").toLowerCase())));
|
|
12200
|
+
}
|
|
12201
|
+
if (f3?.search) pool = pool.filter((i) => `${i.title} ${i.description ?? ""}`.toLowerCase().includes(f3.search.toLowerCase()));
|
|
12202
|
+
if (f3?.updatedAfter) pool = pool.filter((i) => (i.updatedAt ?? "") >= f3.updatedAfter);
|
|
11912
12203
|
const size = Math.max(1, request.pageSize ?? defaultPageSize);
|
|
11913
12204
|
const start = request.cursor ? Math.max(0, Number.parseInt(request.cursor, 10) || 0) : 0;
|
|
11914
12205
|
const slice = pool.slice(start, start + size);
|
|
@@ -11960,6 +12251,9 @@ function configStatus(integration, findings) {
|
|
|
11960
12251
|
if (blocking || !registry.has(integration.adapter)) return "invalid-config";
|
|
11961
12252
|
return "configured";
|
|
11962
12253
|
}
|
|
12254
|
+
function secretResolver(dir, env) {
|
|
12255
|
+
return createCompositeResolver(createLocalSecretProvider(dir), createEnvSecretProvider(env));
|
|
12256
|
+
}
|
|
11963
12257
|
function listIntegrations(dir) {
|
|
11964
12258
|
const { integrations, findings } = loadIntegrations(dir);
|
|
11965
12259
|
return integrations.map((integration) => {
|
|
@@ -11973,6 +12267,9 @@ function listIntegrations(dir) {
|
|
|
11973
12267
|
capabilities: adapter?.capabilities ?? null,
|
|
11974
12268
|
metadata: adapter?.metadata ?? null,
|
|
11975
12269
|
credentialRefs: Object.values(integration.credentials).map((c) => c.env),
|
|
12270
|
+
secretRefs: Object.values(integration.secrets),
|
|
12271
|
+
secretStatus: {},
|
|
12272
|
+
filters: integration.filters,
|
|
11976
12273
|
findings: findings.filter((f3) => f3.id === integration.id)
|
|
11977
12274
|
};
|
|
11978
12275
|
});
|
|
@@ -11981,15 +12278,16 @@ function requireIntegration(dir, id) {
|
|
|
11981
12278
|
const { integrations, findings } = loadIntegrations(dir);
|
|
11982
12279
|
const integration = integrations.find((i) => i.id === id);
|
|
11983
12280
|
if (!integration) throw new IntegrationServiceError("INTEGRATION_NOT_CONFIGURED", `No integration "${id}" is configured in this project.`);
|
|
11984
|
-
return { integration, findings };
|
|
12281
|
+
return { integration, findings, all: integrations };
|
|
11985
12282
|
}
|
|
11986
12283
|
function resolveAdapter(integration) {
|
|
11987
12284
|
const adapter = registry.get(integration.adapter);
|
|
11988
12285
|
if (!adapter) throw new IntegrationServiceError("ADAPTER_NOT_FOUND", `Unknown integration adapter "${integration.adapter}".`);
|
|
11989
12286
|
return adapter;
|
|
11990
12287
|
}
|
|
11991
|
-
function
|
|
11992
|
-
const
|
|
12288
|
+
async function buildContextWithSecrets(dir, integration, env) {
|
|
12289
|
+
const resolver = secretResolver(dir, env);
|
|
12290
|
+
const { credentials, missing } = await resolveAllCredentials(integration, resolver, env);
|
|
11993
12291
|
return {
|
|
11994
12292
|
context: { integrationId: integration.id, config: integration.config, credentials, timeoutMs: integration.timeoutMs ?? DEFAULT_TIMEOUT_MS },
|
|
11995
12293
|
missing
|
|
@@ -12012,7 +12310,7 @@ async function verifyIntegration(dir, id, env = process.env) {
|
|
|
12012
12310
|
if (cfgStatus === "disabled") return { id, status: "disabled", connection: null, missingCredentials: [] };
|
|
12013
12311
|
if (cfgStatus === "invalid-config") return { id, status: "invalid-config", connection: null, missingCredentials: [] };
|
|
12014
12312
|
const adapter = resolveAdapter(integration);
|
|
12015
|
-
const { context, missing } =
|
|
12313
|
+
const { context, missing } = await buildContextWithSecrets(dir, integration, env);
|
|
12016
12314
|
try {
|
|
12017
12315
|
const connection = await withTimeout(adapter.verifyConnection(context), context.timeoutMs);
|
|
12018
12316
|
return { id, status: statusOf(connection), connection, missingCredentials: missing, message: connection.message };
|
|
@@ -12037,14 +12335,15 @@ async function listExternalWorkItems(dir, id, opts = {}, env = process.env) {
|
|
|
12037
12335
|
const { integration } = requireIntegration(dir, id);
|
|
12038
12336
|
const adapter = resolveAdapter(integration);
|
|
12039
12337
|
if (!adapter.capabilities.workItems.list) throw integrationError("UNSUPPORTED_CAPABILITY", `Adapter "${adapter.id}" cannot list work items.`);
|
|
12040
|
-
const { context } =
|
|
12041
|
-
|
|
12338
|
+
const { context } = await buildContextWithSecrets(dir, integration, env);
|
|
12339
|
+
const filters = mergeFilters(integration.filters, opts.filters);
|
|
12340
|
+
return withTimeout(adapter.listWorkItems({ context, cursor: opts.cursor, pageSize: opts.pageSize, filters }), context.timeoutMs);
|
|
12042
12341
|
}
|
|
12043
12342
|
async function getExternalWorkItem(dir, id, externalId, env = process.env) {
|
|
12044
12343
|
const { integration } = requireIntegration(dir, id);
|
|
12045
12344
|
const adapter = resolveAdapter(integration);
|
|
12046
12345
|
if (!adapter.capabilities.workItems.read) throw integrationError("UNSUPPORTED_CAPABILITY", `Adapter "${adapter.id}" cannot read work items.`);
|
|
12047
|
-
const { context } =
|
|
12346
|
+
const { context } = await buildContextWithSecrets(dir, integration, env);
|
|
12048
12347
|
return withTimeout(adapter.getWorkItem({ context, externalId }), context.timeoutMs);
|
|
12049
12348
|
}
|
|
12050
12349
|
|
package/package.json
CHANGED