@cat-factory/agents 0.59.2 → 0.61.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/agents/kinds/ralph.d.ts +18 -0
- package/dist/agents/kinds/ralph.d.ts.map +1 -0
- package/dist/agents/kinds/ralph.js +114 -0
- package/dist/agents/kinds/ralph.js.map +1 -0
- package/dist/agents/kinds/registry.d.ts.map +1 -1
- package/dist/agents/kinds/registry.js +2 -0
- package/dist/agents/kinds/registry.js.map +1 -1
- package/dist/fragmentLibrary/FragmentSourceService.d.ts.map +1 -1
- package/dist/fragmentLibrary/FragmentSourceService.js +49 -66
- package/dist/fragmentLibrary/FragmentSourceService.js.map +1 -1
- package/dist/fragmentLibrary/fragment-source.logic.d.ts.map +1 -1
- package/dist/fragmentLibrary/fragment-source.logic.js +4 -69
- package/dist/fragmentLibrary/fragment-source.logic.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/repoSourceSync/frontmatter.d.ts +12 -0
- package/dist/repoSourceSync/frontmatter.d.ts.map +1 -0
- package/dist/repoSourceSync/frontmatter.js +70 -0
- package/dist/repoSourceSync/frontmatter.js.map +1 -0
- package/dist/repoSourceSync/repo-source-sync.d.ts +88 -0
- package/dist/repoSourceSync/repo-source-sync.d.ts.map +1 -0
- package/dist/repoSourceSync/repo-source-sync.js +50 -0
- package/dist/repoSourceSync/repo-source-sync.js.map +1 -0
- package/dist/skillLibrary/SkillCatalogService.d.ts +35 -0
- package/dist/skillLibrary/SkillCatalogService.d.ts.map +1 -0
- package/dist/skillLibrary/SkillCatalogService.js +52 -0
- package/dist/skillLibrary/SkillCatalogService.js.map +1 -0
- package/dist/skillLibrary/SkillSourceService.d.ts +67 -0
- package/dist/skillLibrary/SkillSourceService.d.ts.map +1 -0
- package/dist/skillLibrary/SkillSourceService.js +237 -0
- package/dist/skillLibrary/SkillSourceService.js.map +1 -0
- package/dist/skillLibrary/skill-source.logic.d.ts +21 -0
- package/dist/skillLibrary/skill-source.logic.d.ts.map +1 -0
- package/dist/skillLibrary/skill-source.logic.js +43 -0
- package/dist/skillLibrary/skill-source.logic.js.map +1 -0
- package/package.json +5 -5
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { NotFoundError, ValidationError, assertFound } from '@cat-factory/kernel';
|
|
2
|
+
import { normalizeDirPath, probeRepoSourceStatus, syncRepoSource, } from '../repoSourceSync/repo-source-sync.js';
|
|
3
|
+
import { isSkillManifest, parseSkillManifest, slugFromDirName } from './skill-source.logic.js';
|
|
4
|
+
/**
|
|
5
|
+
* Repo-sourced Claude skills (docs/initiatives/repo-skills.md): link a repo
|
|
6
|
+
* directory of skill folders to an account, resync it (read each `<skill>/SKILL.md`
|
|
7
|
+
* directory, upsert changed skills, tombstone removed ones), and answer the cheap
|
|
8
|
+
* "check for changes" without writing. Reads go through the account's existing
|
|
9
|
+
* GitHub installation — no new credential store. The shared repo-source engine
|
|
10
|
+
* (repoSourceSync) owns the sync mechanics; this service supplies the skill
|
|
11
|
+
* differentiator: the sync unit is a DIRECTORY (`<skill>/SKILL.md` + its sibling
|
|
12
|
+
* resources), and a resource-only edit (which advances the dir head commit without
|
|
13
|
+
* touching `SKILL.md`'s blob sha) is caught by re-reading whenever the pinned commit
|
|
14
|
+
* moved.
|
|
15
|
+
*/
|
|
16
|
+
export class SkillSourceService {
|
|
17
|
+
deps;
|
|
18
|
+
constructor(deps) {
|
|
19
|
+
this.deps = deps;
|
|
20
|
+
}
|
|
21
|
+
/** Linked sources for an account + their last-synced state. */
|
|
22
|
+
async list(accountId) {
|
|
23
|
+
const rows = await this.deps.skillSourceRepository.listByAccount(accountId);
|
|
24
|
+
return rows.map(toWire);
|
|
25
|
+
}
|
|
26
|
+
/** Link a repo directory as a skill source. Does not sync (call {@link sync}). */
|
|
27
|
+
async link(accountId, input) {
|
|
28
|
+
const now = this.deps.clock.now();
|
|
29
|
+
const record = {
|
|
30
|
+
id: this.deps.idGenerator.next('sklsrc'),
|
|
31
|
+
accountId,
|
|
32
|
+
repoOwner: input.repoOwner.trim(),
|
|
33
|
+
repoName: input.repoName.trim(),
|
|
34
|
+
gitRef: input.gitRef?.trim() || 'HEAD',
|
|
35
|
+
dirPath: normalizeDirPath(input.dirPath),
|
|
36
|
+
lastSyncedCommit: null,
|
|
37
|
+
lastSyncedAt: null,
|
|
38
|
+
createdAt: now,
|
|
39
|
+
deletedAt: null,
|
|
40
|
+
};
|
|
41
|
+
await this.deps.skillSourceRepository.upsert(record);
|
|
42
|
+
return toWire(record);
|
|
43
|
+
}
|
|
44
|
+
/** Unlink a source and tombstone every skill it produced. */
|
|
45
|
+
async unlink(accountId, sourceId) {
|
|
46
|
+
const source = await this.require(accountId, sourceId);
|
|
47
|
+
const now = this.deps.clock.now();
|
|
48
|
+
const skills = await this.deps.accountSkillRepository.listBySource(sourceId);
|
|
49
|
+
if (skills.length > 0) {
|
|
50
|
+
await this.deps.accountSkillRepository.softDeleteBySource(sourceId, now);
|
|
51
|
+
}
|
|
52
|
+
await this.deps.skillSourceRepository.softDelete(source.id, now);
|
|
53
|
+
if (skills.length > 0)
|
|
54
|
+
await this.deps.invalidateCatalog?.(accountId);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Resync a source: read each `<skill>/SKILL.md` directory, upsert every skill whose
|
|
58
|
+
* manifest or resource manifest changed, tombstone skills no longer produced, and
|
|
59
|
+
* stamp the source dir's head commit. Idempotent — re-running with no upstream change
|
|
60
|
+
* touches nothing.
|
|
61
|
+
*/
|
|
62
|
+
async sync(accountId, sourceId) {
|
|
63
|
+
const source = await this.require(accountId, sourceId);
|
|
64
|
+
const installationId = await this.requireInstallation(source);
|
|
65
|
+
return syncRepoSource({
|
|
66
|
+
source,
|
|
67
|
+
installationId,
|
|
68
|
+
githubClient: this.deps.githubClient,
|
|
69
|
+
now: this.deps.clock.now(),
|
|
70
|
+
listExisting: () => this.deps.accountSkillRepository.listBySource(sourceId),
|
|
71
|
+
existingId: (s) => s.skillId,
|
|
72
|
+
reconcile: async ({ readRef, commitMoved, now }, existing) => {
|
|
73
|
+
const existingById = new Map(existing.map((s) => [s.skillId, s]));
|
|
74
|
+
// The head commit for the whole source dir is the exact staleness signal: if it
|
|
75
|
+
// has not advanced since the last sync, NOTHING under it changed (manifest OR
|
|
76
|
+
// resource), so every skill is unchanged and we skip all per-directory reads.
|
|
77
|
+
if (!commitMoved) {
|
|
78
|
+
return {
|
|
79
|
+
liveIds: new Set(existing.map((s) => s.skillId)),
|
|
80
|
+
upserted: 0,
|
|
81
|
+
unchanged: existing.length,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// Sort dirs by name (code-unit order, locale-independent) so slug-collision
|
|
85
|
+
// resolution is deterministic — first wins — regardless of ICU collation.
|
|
86
|
+
const dirs = (await this.listDir(source, installationId, source.dirPath, readRef))
|
|
87
|
+
.filter((e) => e.type === 'dir')
|
|
88
|
+
.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
89
|
+
const liveIds = new Set();
|
|
90
|
+
const seenSlugs = new Set();
|
|
91
|
+
let upserted = 0;
|
|
92
|
+
let unchanged = 0;
|
|
93
|
+
let incomplete = false;
|
|
94
|
+
for (const dir of dirs) {
|
|
95
|
+
const slug = slugFromDirName(dir.name);
|
|
96
|
+
// Two sibling dirs can slug to the same id (e.g. `release_notes` + `release-notes`,
|
|
97
|
+
// both → `release-notes`). Keep the first (sorted order) deterministically and skip
|
|
98
|
+
// the rest rather than silently overwriting one skill's row with another's.
|
|
99
|
+
if (seenSlugs.has(slug))
|
|
100
|
+
continue;
|
|
101
|
+
seenSlugs.add(slug);
|
|
102
|
+
const skillId = `src:${source.id}:${slug}`;
|
|
103
|
+
const synced = await this.syncSkillDir(source, dir.name, dir.path, skillId, existingById.get(skillId), installationId, readRef, now);
|
|
104
|
+
if (synced === 'skip')
|
|
105
|
+
continue;
|
|
106
|
+
// 'kept'/'stale' (both keep a prior row) and 'upserted' all survive the tombstone
|
|
107
|
+
// sweep — a transient failure must never retire an existing skill.
|
|
108
|
+
liveIds.add(skillId);
|
|
109
|
+
if (synced === 'upserted')
|
|
110
|
+
upserted++;
|
|
111
|
+
else
|
|
112
|
+
unchanged++;
|
|
113
|
+
// A detected-but-unapplied change leaves us not caught up to the head commit.
|
|
114
|
+
if (synced === 'stale')
|
|
115
|
+
incomplete = true;
|
|
116
|
+
}
|
|
117
|
+
return { liveIds, upserted, unchanged, incomplete };
|
|
118
|
+
},
|
|
119
|
+
tombstone: (s, now) => this.deps.accountSkillRepository.softDelete(s.accountId, s.skillId, now),
|
|
120
|
+
updateSyncState: (commit, now) => this.deps.skillSourceRepository.updateSyncState(source.id, commit, now),
|
|
121
|
+
invalidate: () => this.deps.invalidateCatalog?.(accountId) ?? Promise.resolve(),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
/** Lightweight "check for changes": one head-commit read compared to the last sync. */
|
|
125
|
+
async status(accountId, sourceId) {
|
|
126
|
+
const source = await this.require(accountId, sourceId);
|
|
127
|
+
const installationId = await this.requireInstallation(source);
|
|
128
|
+
return probeRepoSourceStatus({ source, installationId, githubClient: this.deps.githubClient });
|
|
129
|
+
}
|
|
130
|
+
// --- internals ----------------------------------------------------------
|
|
131
|
+
async require(accountId, sourceId) {
|
|
132
|
+
const source = assertFound(await this.deps.skillSourceRepository.get(sourceId), 'SkillSource', sourceId);
|
|
133
|
+
// The route gate only authorizes the addressed account, so the record must belong
|
|
134
|
+
// to it; 404 hides other accounts' sources entirely.
|
|
135
|
+
if (source.accountId !== accountId)
|
|
136
|
+
throw new NotFoundError('SkillSource', sourceId);
|
|
137
|
+
if (source.deletedAt !== null)
|
|
138
|
+
throw new NotFoundError('SkillSource', sourceId);
|
|
139
|
+
return source;
|
|
140
|
+
}
|
|
141
|
+
async requireInstallation(source) {
|
|
142
|
+
const installationId = await this.deps.resolveInstallationId(source.accountId);
|
|
143
|
+
if (installationId === null) {
|
|
144
|
+
throw new ValidationError('No GitHub installation is available for this account; connect GitHub before syncing a skill source');
|
|
145
|
+
}
|
|
146
|
+
return installationId;
|
|
147
|
+
}
|
|
148
|
+
listDir(source, installationId, path, readRef) {
|
|
149
|
+
return this.deps.githubClient.listDirectory(installationId, { owner: source.repoOwner, repo: source.repoName }, path, readRef);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Reconcile one `<skill>/` directory:
|
|
153
|
+
* - 'skip' — not a skill (no `SKILL.md`), or unreadable/unparseable with NO prior row.
|
|
154
|
+
* - 'kept' — nothing changed; the prior row is current and untouched.
|
|
155
|
+
* - 'stale' — a change WAS detected but couldn't be applied this round (manifest read
|
|
156
|
+
* back as a 404/non-file, or parsed empty) so the prior row is kept alive rather than
|
|
157
|
+
* retired. Signals the caller to leave the source pin behind and retry next sync.
|
|
158
|
+
* - 'upserted' — the manifest or its resource manifest moved and was written.
|
|
159
|
+
*/
|
|
160
|
+
async syncSkillDir(source, dirName, dirPath, skillId, prior, installationId, readRef, now) {
|
|
161
|
+
const entries = await this.listDir(source, installationId, dirPath, readRef);
|
|
162
|
+
const manifest = entries.find((e) => e.type === 'file' && isSkillManifest(e.name));
|
|
163
|
+
if (!manifest)
|
|
164
|
+
return 'skip'; // not a skill directory (SKILL.md removed → prior tombstoned)
|
|
165
|
+
const resources = entries
|
|
166
|
+
.filter((e) => e.type === 'file' && !isSkillManifest(e.name))
|
|
167
|
+
.map((e) => ({ path: e.path, sha: e.sha, size: e.size ?? 0 }))
|
|
168
|
+
.sort((a, b) => a.path.localeCompare(b.path));
|
|
169
|
+
// Fast path: the SKILL.md blob sha is unchanged AND the resource manifest matches,
|
|
170
|
+
// so nothing in this skill changed — keep the prior row untouched.
|
|
171
|
+
if (prior && prior.sourceSha === manifest.sha && sameResources(prior.resources, resources)) {
|
|
172
|
+
return 'kept';
|
|
173
|
+
}
|
|
174
|
+
// Resource-only change: SKILL.md is unchanged but a sibling resource moved. The
|
|
175
|
+
// manifest content (name/description/instructions) is identical, so refresh only the
|
|
176
|
+
// resource manifest + pinned commit without re-fetching the body.
|
|
177
|
+
if (prior && prior.sourceSha === manifest.sha) {
|
|
178
|
+
await this.deps.accountSkillRepository.upsert({
|
|
179
|
+
...prior,
|
|
180
|
+
resources,
|
|
181
|
+
pinnedCommit: readRef,
|
|
182
|
+
updatedAt: now,
|
|
183
|
+
deletedAt: null,
|
|
184
|
+
});
|
|
185
|
+
return 'upserted';
|
|
186
|
+
}
|
|
187
|
+
const file = await this.deps.githubClient.getFileContent(installationId, { owner: source.repoOwner, repo: source.repoName }, manifest.path, readRef);
|
|
188
|
+
// Unreadable / unparseable this round: keep a prior skill alive rather than retiring
|
|
189
|
+
// it over a transient read or an in-progress edit; with no prior there's nothing to keep.
|
|
190
|
+
// Either way a change was detected (the manifest sha moved) but not applied, so report
|
|
191
|
+
// 'stale' so the source pin is NOT advanced and the next sync re-reads.
|
|
192
|
+
if (!file)
|
|
193
|
+
return prior ? 'stale' : 'skip';
|
|
194
|
+
const parsed = parseSkillManifest(dirName, file.content);
|
|
195
|
+
if (!parsed)
|
|
196
|
+
return prior ? 'stale' : 'skip';
|
|
197
|
+
await this.deps.accountSkillRepository.upsert({
|
|
198
|
+
skillId,
|
|
199
|
+
accountId: source.accountId,
|
|
200
|
+
name: parsed.name,
|
|
201
|
+
description: parsed.description,
|
|
202
|
+
instructions: parsed.instructions,
|
|
203
|
+
resources,
|
|
204
|
+
sourceId: source.id,
|
|
205
|
+
sourcePath: manifest.path,
|
|
206
|
+
sourceSha: file.sha,
|
|
207
|
+
pinnedCommit: readRef,
|
|
208
|
+
createdAt: prior?.createdAt ?? now,
|
|
209
|
+
updatedAt: now,
|
|
210
|
+
deletedAt: null,
|
|
211
|
+
});
|
|
212
|
+
return 'upserted';
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
function sameResources(a, b) {
|
|
216
|
+
if (a.length !== b.length)
|
|
217
|
+
return false;
|
|
218
|
+
for (let i = 0; i < a.length; i++) {
|
|
219
|
+
if (a[i].path !== b[i].path || a[i].sha !== b[i].sha)
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
return true;
|
|
223
|
+
}
|
|
224
|
+
function toWire(record) {
|
|
225
|
+
return {
|
|
226
|
+
id: record.id,
|
|
227
|
+
accountId: record.accountId,
|
|
228
|
+
repoOwner: record.repoOwner,
|
|
229
|
+
repoName: record.repoName,
|
|
230
|
+
gitRef: record.gitRef,
|
|
231
|
+
dirPath: record.dirPath,
|
|
232
|
+
lastSyncedCommit: record.lastSyncedCommit,
|
|
233
|
+
lastSyncedAt: record.lastSyncedAt,
|
|
234
|
+
createdAt: record.createdAt,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=SkillSourceService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SkillSourceService.js","sourceRoot":"","sources":["../../src/skillLibrary/SkillSourceService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** A skill parsed from a `SKILL.md` manifest's frontmatter + body. */
|
|
2
|
+
export interface ParsedSkillManifest {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
/** The procedural instructions (the markdown body). */
|
|
6
|
+
instructions: string;
|
|
7
|
+
}
|
|
8
|
+
/** Slug a skill DIRECTORY name into a stable, id-safe token (`Bug Triage` → `bug-triage`). */
|
|
9
|
+
export declare function slugFromDirName(dirName: string): string;
|
|
10
|
+
/** Whether a directory listing entry is a `SKILL.md` manifest (case-insensitive). */
|
|
11
|
+
export declare function isSkillManifest(name: string): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Parse a `SKILL.md` file. Frontmatter carries `name` + `description`; the markdown
|
|
14
|
+
* body is the instructions. Tolerant, mirroring the fragment parser: a missing name
|
|
15
|
+
* defaults to a humanised directory name and a missing description to the first body
|
|
16
|
+
* line, so a sparse manifest still imports. Returns null only when there is no usable
|
|
17
|
+
* body at all — an empty `SKILL.md` is not a skill, and returning null keeps the prior
|
|
18
|
+
* synced row alive rather than retiring a skill over an in-progress edit.
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseSkillManifest(dirName: string, content: string): ParsedSkillManifest | null;
|
|
21
|
+
//# sourceMappingURL=skill-source.logic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-source.logic.d.ts","sourceRoot":"","sources":["../../src/skillLibrary/skill-source.logic.ts"],"names":[],"mappings":"AAQA,sEAAsE;AACtE,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,uDAAuD;IACvD,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,8FAA8F;AAC9F,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAOvD;AAED,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,mBAAmB,GAAG,IAAI,CAQ/F"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { parseSimpleYaml, splitFrontmatter, str } from '../repoSourceSync/frontmatter.js';
|
|
2
|
+
/** Slug a skill DIRECTORY name into a stable, id-safe token (`Bug Triage` → `bug-triage`). */
|
|
3
|
+
export function slugFromDirName(dirName) {
|
|
4
|
+
return (dirName
|
|
5
|
+
.toLowerCase()
|
|
6
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
7
|
+
.replace(/^-+|-+$/g, '') || 'skill');
|
|
8
|
+
}
|
|
9
|
+
/** Whether a directory listing entry is a `SKILL.md` manifest (case-insensitive). */
|
|
10
|
+
export function isSkillManifest(name) {
|
|
11
|
+
return /^skill\.md$/i.test(name);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Parse a `SKILL.md` file. Frontmatter carries `name` + `description`; the markdown
|
|
15
|
+
* body is the instructions. Tolerant, mirroring the fragment parser: a missing name
|
|
16
|
+
* defaults to a humanised directory name and a missing description to the first body
|
|
17
|
+
* line, so a sparse manifest still imports. Returns null only when there is no usable
|
|
18
|
+
* body at all — an empty `SKILL.md` is not a skill, and returning null keeps the prior
|
|
19
|
+
* synced row alive rather than retiring a skill over an in-progress edit.
|
|
20
|
+
*/
|
|
21
|
+
export function parseSkillManifest(dirName, content) {
|
|
22
|
+
const { frontmatter, body } = splitFrontmatter(content);
|
|
23
|
+
const fm = parseSimpleYaml(frontmatter);
|
|
24
|
+
const instructions = body.trim();
|
|
25
|
+
if (!instructions)
|
|
26
|
+
return null;
|
|
27
|
+
const name = str(fm.name) ?? humanise(dirName);
|
|
28
|
+
const description = str(fm.description) ?? firstLine(instructions) ?? name;
|
|
29
|
+
return { name, description, instructions };
|
|
30
|
+
}
|
|
31
|
+
// --- internals ------------------------------------------------------------
|
|
32
|
+
function firstLine(body) {
|
|
33
|
+
const line = body
|
|
34
|
+
.split(/\r?\n/)
|
|
35
|
+
.map((l) => l.replace(/^[#>\-*\s]+/, '').trim())
|
|
36
|
+
.find((l) => l.length > 0);
|
|
37
|
+
return line ? line.slice(0, 200) : undefined;
|
|
38
|
+
}
|
|
39
|
+
function humanise(dirName) {
|
|
40
|
+
const stem = dirName.replace(/[-_]+/g, ' ').trim();
|
|
41
|
+
return stem ? stem.charAt(0).toUpperCase() + stem.slice(1) : 'Skill';
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=skill-source.logic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-source.logic.js","sourceRoot":"","sources":["../../src/skillLibrary/skill-source.logic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,GAAG,EAAE,MAAM,kCAAkC,CAAA;AAgBzF,8FAA8F;AAC9F,MAAM,UAAU,eAAe,CAAC,OAAe;IAC7C,OAAO,CACL,OAAO;SACJ,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CACtC,CAAA;AACH,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAClC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe,EAAE,OAAe;IACjE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAA;IACvD,MAAM,EAAE,GAAG,eAAe,CAAC,WAAW,CAAC,CAAA;IACvC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;IAChC,IAAI,CAAC,YAAY;QAAE,OAAO,IAAI,CAAA;IAC9B,MAAM,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAA;IAC9C,MAAM,WAAW,GAAG,GAAG,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,SAAS,CAAC,YAAY,CAAC,IAAI,IAAI,CAAA;IAC1E,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,CAAA;AAC5C,CAAC;AAED,6EAA6E;AAE7E,SAAS,SAAS,CAAC,IAAY;IAC7B,MAAM,IAAI,GAAG,IAAI;SACd,KAAK,CAAC,OAAO,CAAC;SACd,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;SAC/C,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAC5B,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;AAC9C,CAAC;AAED,SAAS,QAAQ,CAAC,OAAe;IAC/B,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAA;IAClD,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAA;AACtE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/agents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.61.0",
|
|
4
4
|
"description": "Agent catalog, routing, prompts and fragment library for the Agent Architecture Board.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
"ai": "^6.0.224",
|
|
32
32
|
"handlebars": "^4.7.9",
|
|
33
33
|
"valibot": "^1.4.2",
|
|
34
|
-
"@cat-factory/contracts": "0.
|
|
35
|
-
"@cat-factory/kernel": "0.
|
|
36
|
-
"@cat-factory/prompt-fragments": "0.13.
|
|
34
|
+
"@cat-factory/contracts": "0.137.0",
|
|
35
|
+
"@cat-factory/kernel": "0.131.0",
|
|
36
|
+
"@cat-factory/prompt-fragments": "0.13.26"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"typescript": "7.0.2",
|
|
40
40
|
"vitest": "^4.1.10",
|
|
41
|
-
"@cat-factory/caching": "0.
|
|
41
|
+
"@cat-factory/caching": "0.9.0"
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
44
|
"build": "tsc -b tsconfig.build.json",
|