@cat-factory/integrations 0.141.2 → 0.142.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.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/modules/tasks/GitHubIssuesProvider.d.ts +8 -0
- package/dist/modules/tasks/GitHubIssuesProvider.d.ts.map +1 -1
- package/dist/modules/tasks/GitHubIssuesProvider.js +5 -0
- package/dist/modules/tasks/GitHubIssuesProvider.js.map +1 -1
- package/dist/modules/tasks/GitLabIssuesProvider.d.ts +126 -0
- package/dist/modules/tasks/GitLabIssuesProvider.d.ts.map +1 -0
- package/dist/modules/tasks/GitLabIssuesProvider.js +251 -0
- package/dist/modules/tasks/GitLabIssuesProvider.js.map +1 -0
- package/dist/modules/tasks/TaskConnectionService.d.ts +8 -6
- package/dist/modules/tasks/TaskConnectionService.d.ts.map +1 -1
- package/dist/modules/tasks/TaskConnectionService.js +64 -26
- package/dist/modules/tasks/TaskConnectionService.js.map +1 -1
- package/dist/modules/tasks/TaskImportService.d.ts +10 -4
- package/dist/modules/tasks/TaskImportService.d.ts.map +1 -1
- package/dist/modules/tasks/TaskImportService.js +19 -6
- package/dist/modules/tasks/TaskImportService.js.map +1 -1
- package/dist/modules/tasks/github-issues.logic.d.ts +10 -0
- package/dist/modules/tasks/github-issues.logic.d.ts.map +1 -1
- package/dist/modules/tasks/github-issues.logic.js +13 -0
- package/dist/modules/tasks/github-issues.logic.js.map +1 -1
- package/dist/modules/tasks/gitlab-issues.logic.d.ts +106 -0
- package/dist/modules/tasks/gitlab-issues.logic.d.ts.map +1 -0
- package/dist/modules/tasks/gitlab-issues.logic.js +186 -0
- package/dist/modules/tasks/gitlab-issues.logic.js.map +1 -0
- package/dist/modules/tasks/tasks.logic.d.ts +14 -8
- package/dist/modules/tasks/tasks.logic.d.ts.map +1 -1
- package/dist/modules/tasks/tasks.logic.js +17 -15
- package/dist/modules/tasks/tasks.logic.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// GitLab-issues task-source pure logic, the sibling of `github-issues.logic.ts`: the
|
|
2
|
+
// descriptor, the external-id grammar and its round-trip, the ref parser, and the
|
|
3
|
+
// project-scoped search query. Pure, so every rule below is unit-testable without a
|
|
4
|
+
// live API; the fetch itself lives in `GitLabIssuesProvider`.
|
|
5
|
+
//
|
|
6
|
+
// The one structural difference from the GitHub logic drives most of this file: a GitLab
|
|
7
|
+
// project path NESTS. `group/sub/project` is a legal project, and the client folds it into
|
|
8
|
+
// `{ owner: 'group/sub', repo: 'project' }` (splitting at the LAST slash, the same way
|
|
9
|
+
// GitLab's own web URLs read), so an owner here is a multi-segment path where GitHub's is
|
|
10
|
+
// a single account name. Reusing the GitHub grammar would not merely be inconvenient: a
|
|
11
|
+
// subgroup issue would round-trip through it as garbage rather than as a refusal.
|
|
12
|
+
//
|
|
13
|
+
// GitLab issue descriptions are already Markdown, so there is no body-conversion step.
|
|
14
|
+
/**
|
|
15
|
+
* What the connect UI renders. GitLab issues ride the workspace's existing VCS connection
|
|
16
|
+
* (the `provider: 'gitlab'` row a PAT connect writes), so there are NO credential fields —
|
|
17
|
+
* the same credentialless shape GitHub Issues has, keyed on a different connection.
|
|
18
|
+
*/
|
|
19
|
+
export const GITLAB_ISSUES_DESCRIPTOR = {
|
|
20
|
+
source: 'gitlab',
|
|
21
|
+
label: 'GitLab Issues',
|
|
22
|
+
icon: 'i-lucide-gitlab',
|
|
23
|
+
credentialFields: [],
|
|
24
|
+
refLabel: 'Issue URL or group/project#number',
|
|
25
|
+
refPlaceholder: 'acme/web#123 or https://gitlab.com/acme/web/-/issues/123',
|
|
26
|
+
searchable: true,
|
|
27
|
+
};
|
|
28
|
+
/** The canonical `group/sub/project#iid` external id for an issue's parts. */
|
|
29
|
+
export function gitlabIssueExternalId(id) {
|
|
30
|
+
return `${id.owner}/${id.repo}#${id.number}`;
|
|
31
|
+
}
|
|
32
|
+
// A single path segment of a GitLab project path: letters, digits, '.', '_' and '-'.
|
|
33
|
+
const SEG = '[A-Za-z0-9._-]+';
|
|
34
|
+
// A full project path: at least two segments (a namespace and the project), and possibly
|
|
35
|
+
// more, because GitLab nests subgroups. Non-greedy up to the LAST slash so the split below
|
|
36
|
+
// matches how the client folds a web URL.
|
|
37
|
+
const PROJECT_PATH = `${SEG}(?:/${SEG})+`;
|
|
38
|
+
/**
|
|
39
|
+
* Split a project path at its LAST slash, which is the same fold the GitLab client applies
|
|
40
|
+
* to a `web_url`: everything before is the namespace (`group/sub`), the final segment is the
|
|
41
|
+
* project. Returns null for a path with no slash, i.e. one that names no project.
|
|
42
|
+
*/
|
|
43
|
+
function splitProjectPath(path) {
|
|
44
|
+
const idx = path.lastIndexOf('/');
|
|
45
|
+
if (idx <= 0 || idx === path.length - 1)
|
|
46
|
+
return null;
|
|
47
|
+
return { owner: path.slice(0, idx), repo: path.slice(idx + 1) };
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Resolve a GitLab issue reference from raw user input into the canonical
|
|
51
|
+
* `group/sub/project#iid` external id. Accepts:
|
|
52
|
+
* - a full issue URL: `https://gitlab.example.com/acme/sub/web/-/issues/123`
|
|
53
|
+
* - the `acme/sub/web/-/issues/123` path form
|
|
54
|
+
* - the shorthand `acme/sub/web#123`
|
|
55
|
+
* Returns null when nothing parses. Path segments are kept verbatim (a GitLab path is
|
|
56
|
+
* case-sensitive in a way GitHub's is not); only surrounding whitespace is trimmed.
|
|
57
|
+
*
|
|
58
|
+
* The URL form matches the `/-/issues/` separator GitLab puts between a project path and a
|
|
59
|
+
* resource, which is also what makes an arbitrarily deep project path unambiguous: without
|
|
60
|
+
* it there would be no way to tell where the path ends and `issues/123` begins.
|
|
61
|
+
*/
|
|
62
|
+
export function parseGitLabIssueRef(input) {
|
|
63
|
+
const trimmed = input.trim();
|
|
64
|
+
const url = trimmed.match(new RegExp(`^https?://[^/]+/(${PROJECT_PATH})/-/issues/(\\d+)`));
|
|
65
|
+
if (url)
|
|
66
|
+
return `${url[1]}#${url[2]}`;
|
|
67
|
+
const path = trimmed.match(new RegExp(`^(${PROJECT_PATH})/-/issues/(\\d+)$`));
|
|
68
|
+
if (path)
|
|
69
|
+
return `${path[1]}#${path[2]}`;
|
|
70
|
+
const short = trimmed.match(new RegExp(`^(${PROJECT_PATH})#(\\d+)$`));
|
|
71
|
+
if (short)
|
|
72
|
+
return `${short[1]}#${short[2]}`;
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Split a stored `group/sub/project#iid` external id back into its parts. Returns null if
|
|
77
|
+
* the id is malformed (defensive — ids are produced by {@link parseGitLabIssueRef}, but a
|
|
78
|
+
* stale or hand-edited row should not throw).
|
|
79
|
+
*/
|
|
80
|
+
export function parseGitLabIssueExternalId(externalId) {
|
|
81
|
+
const m = externalId.match(new RegExp(`^(${PROJECT_PATH})#(\\d+)$`));
|
|
82
|
+
if (!m)
|
|
83
|
+
return null;
|
|
84
|
+
const parts = splitProjectPath(m[1]);
|
|
85
|
+
if (!parts)
|
|
86
|
+
return null;
|
|
87
|
+
return { owner: parts.owner, repo: parts.repo, number: Number(m[2]) };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Build an issue's web URL from the deployment's GitLab web base, for the one case where the
|
|
91
|
+
* API answered without a `web_url` of its own.
|
|
92
|
+
*
|
|
93
|
+
* There is deliberately no constant fallback: a self-managed GitLab lives at the
|
|
94
|
+
* deployment's own host, so `gitlab.com` would not be a guess that is usually right, it
|
|
95
|
+
* would be a link to a stranger's instance. `undefined` in, `''` out — an empty URL renders
|
|
96
|
+
* as no link, where a wrong one renders as a link to the wrong issue.
|
|
97
|
+
*/
|
|
98
|
+
export function gitlabIssueUrl(id, webBaseUrl) {
|
|
99
|
+
const base = webBaseUrl?.replace(/\/+$/, '');
|
|
100
|
+
if (!base)
|
|
101
|
+
return '';
|
|
102
|
+
return `${base}/${id.owner}/${id.repo}/-/issues/${id.number}`;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Derive the GitLab WEB base from the configured API base, which is the same host with the
|
|
106
|
+
* REST prefix on the end (`https://gitlab.example.com/api/v4`). Returns undefined for an
|
|
107
|
+
* absent/unparseable value rather than a guess, so {@link gitlabIssueUrl} withholds its link.
|
|
108
|
+
*/
|
|
109
|
+
export function gitlabWebBaseFromApiBase(apiBase) {
|
|
110
|
+
const trimmed = apiBase?.trim().replace(/\/+$/, '');
|
|
111
|
+
if (!trimmed)
|
|
112
|
+
return undefined;
|
|
113
|
+
const stripped = trimmed.replace(/\/api\/v\d+$/, '');
|
|
114
|
+
return stripped || undefined;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The provider's `TaskRepoScopeRules` matcher: whether a STORED external id belongs to the
|
|
118
|
+
* scoped project.
|
|
119
|
+
*
|
|
120
|
+
* Case-SENSITIVE, where the GitHub twin is not, and that asymmetry is the whole reason the
|
|
121
|
+
* comparison belongs to the source rather than to a shared helper. A GitLab project path is the
|
|
122
|
+
* `path_with_namespace` both sides are built from (the id is parsed out of a `web_url`, the scope
|
|
123
|
+
* comes from the repo projection's own fold of the same field), so they already agree; folding
|
|
124
|
+
* case on top would let `Acme/web` and `acme/web`, which GitLab serves as two different projects,
|
|
125
|
+
* answer for each other.
|
|
126
|
+
*
|
|
127
|
+
* An id that does not parse is out of scope, same reading as the GitHub matcher's.
|
|
128
|
+
*/
|
|
129
|
+
export function gitlabIssueInRepoScope(externalId, scope) {
|
|
130
|
+
const id = parseGitLabIssueExternalId(externalId);
|
|
131
|
+
return !!id && id.owner === scope.owner && id.repo === scope.repo;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Build the project-scoped issue search for the picker's free-text box. The scope is the
|
|
135
|
+
* repository the searching service frame is linked to, and it is an ARGUMENT of the request
|
|
136
|
+
* rather than text in the query, so there is no unscoped spelling of this search to reach by
|
|
137
|
+
* accident — see the kernel port's note on why GitLab in particular cannot express the scope
|
|
138
|
+
* as a qualifier.
|
|
139
|
+
*
|
|
140
|
+
* Both states are searched, not just open ones: a picker attaches an issue for CONTEXT, and
|
|
141
|
+
* a closed issue is routinely the one a follow-up task points at. (The intake/hunt reads,
|
|
142
|
+
* which pick work to START, are the ones that set `openOnly`.)
|
|
143
|
+
*/
|
|
144
|
+
export function buildGitLabIssueSearchQuery(query, limit) {
|
|
145
|
+
const text = query.trim();
|
|
146
|
+
return { limit, ...(text ? { text } : {}) };
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Resolve raw search input that names ONE specific issue in the SCOPED project (rather than
|
|
150
|
+
* free text) into its canonical external id, so the caller can fetch it and offer it as the
|
|
151
|
+
* exact match. Two forms, mirroring the GitHub logic's:
|
|
152
|
+
* 1. An explicit reference (issue URL, `/-/issues/` path, or `group/project#n` shorthand),
|
|
153
|
+
* accepted only when it names the SCOPED project.
|
|
154
|
+
* 2. A bare issue number, resolved against `scope` — the only way to know which project a
|
|
155
|
+
* lone number belongs to.
|
|
156
|
+
* Returns null when the input is neither (treat it as free-text search).
|
|
157
|
+
*
|
|
158
|
+
* A reference naming a DIFFERENT project resolves to null on purpose: a search returns the
|
|
159
|
+
* service's own project and nothing else, so a stray paste can never be dressed up as a hit
|
|
160
|
+
* the search found. Linking that issue is still supported through the picker's explicit
|
|
161
|
+
* attach-by-reference row, which imports the ref directly.
|
|
162
|
+
*
|
|
163
|
+
* Unlike the GitHub twin the comparison is case-SENSITIVE, and the id is echoed from the
|
|
164
|
+
* scope for the same reason that one is: GitLab project paths are lowercase by construction
|
|
165
|
+
* but their display forms are not, and an external id is stored verbatim, so normalising
|
|
166
|
+
* here is what stops one issue becoming two rows.
|
|
167
|
+
*/
|
|
168
|
+
export function detectExactGitLabIssueRef(query, scope) {
|
|
169
|
+
const trimmed = query.trim();
|
|
170
|
+
const ref = parseGitLabIssueRef(trimmed);
|
|
171
|
+
if (ref) {
|
|
172
|
+
const id = parseGitLabIssueExternalId(ref);
|
|
173
|
+
if (!id || id.owner !== scope.owner || id.repo !== scope.repo)
|
|
174
|
+
return null;
|
|
175
|
+
return gitlabIssueExternalId({ owner: scope.owner, repo: scope.repo, number: id.number });
|
|
176
|
+
}
|
|
177
|
+
if (/^\d+$/.test(trimmed)) {
|
|
178
|
+
return gitlabIssueExternalId({
|
|
179
|
+
owner: scope.owner,
|
|
180
|
+
repo: scope.repo,
|
|
181
|
+
number: Number(trimmed),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=gitlab-issues.logic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitlab-issues.logic.js","sourceRoot":"","sources":["../../../src/modules/tasks/gitlab-issues.logic.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,15 +10,21 @@ export declare class MapTaskSourceRegistry extends MapSourceRegistry<TaskSourceK
|
|
|
10
10
|
/** A short plain-text excerpt of an issue: its summary + the start of its description. */
|
|
11
11
|
export declare function buildTaskExcerpt(content: TaskContent | TaskRecord, max?: number): string;
|
|
12
12
|
/**
|
|
13
|
-
* Whether an imported task belongs to a repo scope
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
13
|
+
* Whether an imported task belongs to a repo scope, asked of the source that minted its
|
|
14
|
+
* external id: a repo-backed provider (GitHub Issues, GitLab Issues) declares `repoScope` and
|
|
15
|
+
* owns the comparison, because the id GRAMMAR and its case rules are the source's own.
|
|
16
|
+
*
|
|
17
|
+
* A source with no `repoScope` passes unfiltered, and that covers two different situations that
|
|
18
|
+
* happen to want the same answer. A repo-LESS source (Jira, Linear) has no repository to be
|
|
19
|
+
* narrowed to, so the scope simply does not apply to its rows. An UNREGISTERED source (a row
|
|
20
|
+
* left behind by a provider this deployment no longer wires) has no rule available to judge it
|
|
21
|
+
* by, and dropping a row a scope cannot evaluate would silently shrink the list rather than
|
|
22
|
+
* narrow it: the reader would read the absence as "this service has no such issue".
|
|
23
|
+
*
|
|
24
|
+
* Passing the provider rather than looking it up here keeps this pure, and lets the caller
|
|
25
|
+
* resolve each source ONCE for a whole list instead of per row.
|
|
20
26
|
*/
|
|
21
|
-
export declare function taskInRepoScope(record: Pick<TaskRecord, 'source' | 'externalId'>, scope: TaskSearchRepoScope): boolean;
|
|
27
|
+
export declare function taskInRepoScope(record: Pick<TaskRecord, 'source' | 'externalId'>, scope: TaskSearchRepoScope, provider: TaskSourceProvider | undefined): boolean;
|
|
22
28
|
/**
|
|
23
29
|
* Read a numeric HTTP status off a thrown error, if it carries one. Both the
|
|
24
30
|
* GitHub (`GitHubApiError`) and Jira (`JiraApiError`) clients expose a `status`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tasks.logic.d.ts","sourceRoot":"","sources":["../../../src/modules/tasks/tasks.logic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAC9E,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAC9F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EAAgC,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"tasks.logic.d.ts","sourceRoot":"","sources":["../../../src/modules/tasks/tasks.logic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAC9E,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAC9F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EAAgC,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAErF,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAQvD,4EAA4E;AAC5E,qBAAa,qBACX,SAAQ,iBAAiB,CAAC,cAAc,EAAE,kBAAkB,CAC5D,YAAW,kBAAkB;CAAG;AAElC,0FAA0F;AAC1F,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,UAAU,EAAE,GAAG,SAAM,GAAG,MAAM,CAIrF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,QAAQ,GAAG,YAAY,CAAC,EACjD,KAAK,EAAE,mBAAmB,EAC1B,QAAQ,EAAE,kBAAkB,GAAG,SAAS,GACvC,OAAO,CAIT;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAMxD"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { markdownToText, buildExcerpt, MapSourceRegistry } from '@cat-factory/kernel';
|
|
2
|
-
import { parseGitHubIssueExternalId } from './github-issues.logic.js';
|
|
3
2
|
export { renderTaskContext } from '@cat-factory/kernel';
|
|
4
3
|
// Source-agnostic helpers shared by every task source: a trivial provider
|
|
5
4
|
// registry, deriving a plain-text excerpt from an issue, and rendering an issue
|
|
@@ -16,22 +15,25 @@ export function buildTaskExcerpt(content, max = 280) {
|
|
|
16
15
|
return buildExcerpt(lead, max);
|
|
17
16
|
}
|
|
18
17
|
/**
|
|
19
|
-
* Whether an imported task belongs to a repo scope
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
18
|
+
* Whether an imported task belongs to a repo scope, asked of the source that minted its
|
|
19
|
+
* external id: a repo-backed provider (GitHub Issues, GitLab Issues) declares `repoScope` and
|
|
20
|
+
* owns the comparison, because the id GRAMMAR and its case rules are the source's own.
|
|
21
|
+
*
|
|
22
|
+
* A source with no `repoScope` passes unfiltered, and that covers two different situations that
|
|
23
|
+
* happen to want the same answer. A repo-LESS source (Jira, Linear) has no repository to be
|
|
24
|
+
* narrowed to, so the scope simply does not apply to its rows. An UNREGISTERED source (a row
|
|
25
|
+
* left behind by a provider this deployment no longer wires) has no rule available to judge it
|
|
26
|
+
* by, and dropping a row a scope cannot evaluate would silently shrink the list rather than
|
|
27
|
+
* narrow it: the reader would read the absence as "this service has no such issue".
|
|
28
|
+
*
|
|
29
|
+
* Passing the provider rather than looking it up here keeps this pure, and lets the caller
|
|
30
|
+
* resolve each source ONCE for a whole list instead of per row.
|
|
26
31
|
*/
|
|
27
|
-
export function taskInRepoScope(record, scope) {
|
|
28
|
-
|
|
32
|
+
export function taskInRepoScope(record, scope, provider) {
|
|
33
|
+
const rules = provider?.repoScope;
|
|
34
|
+
if (!rules)
|
|
29
35
|
return true;
|
|
30
|
-
|
|
31
|
-
if (!parts)
|
|
32
|
-
return false;
|
|
33
|
-
return (parts.owner.toLowerCase() === scope.owner.toLowerCase() &&
|
|
34
|
-
parts.repo.toLowerCase() === scope.repo.toLowerCase());
|
|
36
|
+
return rules.matches(record.externalId, scope);
|
|
35
37
|
}
|
|
36
38
|
/**
|
|
37
39
|
* Read a numeric HTTP status off a thrown error, if it carries one. Both the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tasks.logic.js","sourceRoot":"","sources":["../../../src/modules/tasks/tasks.logic.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;
|
|
1
|
+
{"version":3,"file":"tasks.logic.js","sourceRoot":"","sources":["../../../src/modules/tasks/tasks.logic.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAGrF,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AAEvD,0EAA0E;AAC1E,gFAAgF;AAChF,kFAAkF;AAClF,yEAAyE;AACzE,sEAAsE;AAEtE,4EAA4E;AAC5E,MAAM,OAAO,qBACX,SAAQ,iBAAqD;CAC7B;AAElC,0FAA0F;AAC1F,MAAM,UAAU,gBAAgB,CAAC,OAAiC,EAAE,GAAG,GAAG,GAAG;IAC3E,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;IACvD,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,MAAM,WAAW,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAA;IAC9E,OAAO,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;AAChC,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAiD,EACjD,KAA0B,EAC1B,QAAwC;IAExC,MAAM,KAAK,GAAG,QAAQ,EAAE,SAAS,CAAA;IACjC,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IACvB,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,CAAA;AAChD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,GAAY;IACvC,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,QAAQ,IAAI,GAAG,EAAE,CAAC;QACtD,MAAM,MAAM,GAAI,GAA2B,CAAC,MAAM,CAAA;QAClD,IAAI,OAAO,MAAM,KAAK,QAAQ;YAAE,OAAO,MAAM,CAAA;IAC/C,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/integrations",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.142.0",
|
|
4
4
|
"description": "External-system integration domain logic for the Agent Architecture Board (GitHub, documents, tasks, environments, runners).",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -27,15 +27,15 @@
|
|
|
27
27
|
"ai": "^7.0.51",
|
|
28
28
|
"p-map": "^7.0.6",
|
|
29
29
|
"yaml": "^2.9.0",
|
|
30
|
-
"@cat-factory/
|
|
31
|
-
"@cat-factory/
|
|
30
|
+
"@cat-factory/contracts": "0.265.0",
|
|
31
|
+
"@cat-factory/kernel": "0.263.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"typescript": "7.0.2",
|
|
35
35
|
"undici": "^8.10.0",
|
|
36
36
|
"valibot": "^1.4.2",
|
|
37
37
|
"vitest": "^4.1.10",
|
|
38
|
-
"@cat-factory/caching": "0.18.
|
|
38
|
+
"@cat-factory/caching": "0.18.4"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
41
|
"build": "tsc -b tsconfig.build.json",
|