@exellix/ai-skills 6.5.0 → 6.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/README.md +15 -0
- package/dist/catalog-manager/createAiSkillsCatalogApi.d.ts +8 -0
- package/dist/catalog-manager/createAiSkillsCatalogApi.d.ts.map +1 -0
- package/dist/catalog-manager/createAiSkillsCatalogApi.js +144 -0
- package/dist/catalog-manager/createAiSkillsCatalogApi.js.map +1 -0
- package/dist/catalog-manager/index.d.ts +3 -0
- package/dist/catalog-manager/index.d.ts.map +1 -0
- package/dist/catalog-manager/index.js +2 -0
- package/dist/catalog-manager/index.js.map +1 -0
- package/dist/catalog-manager/types.d.ts +71 -0
- package/dist/catalog-manager/types.d.ts.map +1 -0
- package/dist/catalog-manager/types.js +2 -0
- package/dist/catalog-manager/types.js.map +1 -0
- package/dist/catalox/ai-skills-catalog.d.ts +12 -15
- package/dist/catalox/ai-skills-catalog.d.ts.map +1 -1
- package/dist/catalox/ai-skills-catalog.js +23 -143
- package/dist/catalox/ai-skills-catalog.js.map +1 -1
- package/dist/catalox/ai-sub-skills-catalog.d.ts +7 -0
- package/dist/catalox/ai-sub-skills-catalog.d.ts.map +1 -0
- package/dist/catalox/ai-sub-skills-catalog.js +72 -0
- package/dist/catalox/ai-sub-skills-catalog.js.map +1 -0
- package/dist/catalox/catalog-guards.d.ts +14 -0
- package/dist/catalox/catalog-guards.d.ts.map +1 -0
- package/dist/catalox/catalog-guards.js +86 -0
- package/dist/catalox/catalog-guards.js.map +1 -0
- package/dist/catalox/catalog-native-store.d.ts +21 -0
- package/dist/catalox/catalog-native-store.d.ts.map +1 -0
- package/dist/catalox/catalog-native-store.js +101 -0
- package/dist/catalox/catalog-native-store.js.map +1 -0
- package/dist/catalox/catalog-normalization.d.ts +70 -0
- package/dist/catalox/catalog-normalization.d.ts.map +1 -0
- package/dist/catalox/catalog-normalization.js +281 -0
- package/dist/catalox/catalog-normalization.js.map +1 -0
- package/dist/catalox/index.d.ts +5 -4
- package/dist/catalox/index.d.ts.map +1 -1
- package/dist/catalox/index.js +5 -4
- package/dist/catalox/index.js.map +1 -1
- package/dist/catalox/list-ai-skills-catalog.d.ts +12 -6
- package/dist/catalox/list-ai-skills-catalog.d.ts.map +1 -1
- package/dist/catalox/list-ai-skills-catalog.js +72 -19
- package/dist/catalox/list-ai-skills-catalog.js.map +1 -1
- package/dist/catalox/skill-optimixer-catalog.d.ts +16 -15
- package/dist/catalox/skill-optimixer-catalog.d.ts.map +1 -1
- package/dist/catalox/skill-optimixer-catalog.js +67 -70
- package/dist/catalox/skill-optimixer-catalog.js.map +1 -1
- package/dist/catalox/skill-template-catalog-mutations.d.ts +12 -52
- package/dist/catalox/skill-template-catalog-mutations.d.ts.map +1 -1
- package/dist/catalox/skill-template-catalog-mutations.js +288 -329
- package/dist/catalox/skill-template-catalog-mutations.js.map +1 -1
- package/dist/catalox/skill-templates.d.ts +32 -43
- package/dist/catalox/skill-templates.d.ts.map +1 -1
- package/dist/catalox/skill-templates.js +66 -50
- package/dist/catalox/skill-templates.js.map +1 -1
- package/dist/client/registry-manager.d.ts +2 -2
- package/dist/client/registry-manager.d.ts.map +1 -1
- package/dist/client/registry-manager.js +5 -5
- package/dist/client/registry-manager.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/invocation/defaultAiProfilesResolveOptions.d.ts +1 -1
- package/dist/invocation/defaultAiProfilesResolveOptions.d.ts.map +1 -1
- package/dist/invocation/defaultAiProfilesResolveOptions.js +2 -2
- package/dist/invocation/defaultAiProfilesResolveOptions.js.map +1 -1
- package/dist/invocation/normalizeModelConfigForGatewayInvoke.js +2 -2
- package/dist/invocation/normalizeModelConfigForGatewayInvoke.js.map +1 -1
- package/dist/invocation/preferOpenRouterPolicy.d.ts +2 -3
- package/dist/invocation/preferOpenRouterPolicy.d.ts.map +1 -1
- package/dist/invocation/preferOpenRouterPolicy.js +6 -11
- package/dist/invocation/preferOpenRouterPolicy.js.map +1 -1
- package/dist/invocation/resolveSkillProfileToWireModel.js +3 -3
- package/dist/invocation/resolveSkillProfileToWireModel.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +8 -5
|
@@ -1,19 +1,15 @@
|
|
|
1
|
-
import { copySkillOptimixerCatalogDataFields, skillOptimixerCatalogSpecToDataFields, } from "./skill-optimixer-catalog.js";
|
|
2
1
|
import { AI_SKILLS_CATALOG_ID, computeSkillRowStatus } from "./ai-skills-catalog.js";
|
|
2
|
+
import { AI_SUB_SKILLS_CATALOG_ID } from "./ai-sub-skills-catalog.js";
|
|
3
|
+
import { buildAiSkillsBaseWriteRecord, buildAiSubSkillsWriteRecord, computeSubSkillOverrides, resolveBaseSkillFromRecord, readIndexedParentSkillKey, } from "./catalog-normalization.js";
|
|
4
|
+
import { getNativeCatalogRecord, replaceNativeCatalogRecord, deleteNativeCatalogRecordByItemId } from "./catalog-native-store.js";
|
|
3
5
|
import { CataloxSkillAlreadyExistsError, CataloxSkillNotFoundError } from "./catalox-skill-errors.js";
|
|
4
|
-
import {
|
|
6
|
+
import { defaultSkillOptimixerCatalogSpecForTests } from "./skill-optimixer-catalog.js";
|
|
7
|
+
import { catalogItemIdFromSkillKey, resolveSkillRuntimeFromCatalogs, } from "./skill-templates.js";
|
|
5
8
|
import { extractTemplateTokensFromTexts, extractTokenNamesFromStrings, normalizeForStorage, toPresentationMarkdown, } from "./skill-template-markdown.js";
|
|
6
|
-
/** Stable role ids for template bodies (matches Catalox `*Text` fields). */
|
|
7
9
|
export const SKILL_TEMPLATE_ROLES_ORDER = ["instructions", "prompt", "auditInstructions", "auditPrompt"];
|
|
8
10
|
function isSkillTemplateRole(s) {
|
|
9
11
|
return SKILL_TEMPLATE_ROLES_ORDER.includes(s);
|
|
10
12
|
}
|
|
11
|
-
function appendParentSkillKeyIfPresent(data, payload) {
|
|
12
|
-
const p = asString(data.parentSkillKey);
|
|
13
|
-
if (p.length > 0) {
|
|
14
|
-
payload.parentSkillKey = p;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
13
|
function asSkillCatalogStatus(v) {
|
|
18
14
|
if (v === "draft" || v === "published" || v === "planned")
|
|
19
15
|
return v;
|
|
@@ -22,36 +18,27 @@ function asSkillCatalogStatus(v) {
|
|
|
22
18
|
function asString(v) {
|
|
23
19
|
return typeof v === "string" ? v : "";
|
|
24
20
|
}
|
|
25
|
-
/**
|
|
26
|
-
* Loads skill template bodies from Catalox and returns markdown formatted for editors / presentation.
|
|
27
|
-
* Requires Catalox read access for `appId` + catalog binding.
|
|
28
|
-
*/
|
|
29
21
|
export async function getSkillTemplatesForPresentation(catalox, context, skillKey, options = {}) {
|
|
22
|
+
void catalox;
|
|
23
|
+
void context;
|
|
30
24
|
const catalogItemId = catalogItemIdFromSkillKey(skillKey);
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
if (res.outcome === "mapping_blocked") {
|
|
36
|
-
throw new Error(`[AI-SKILLS] Catalox mapping blocked for skill ${catalogItemId}`);
|
|
37
|
-
}
|
|
38
|
-
const data = (res.item.data ?? {});
|
|
39
|
-
const shortKey = asString(data.skillKey) || catalogItemId;
|
|
40
|
-
const ins = asString(data.instructionsText);
|
|
41
|
-
const pr = asString(data.promptText);
|
|
25
|
+
const resolved = await resolveSkillRuntimeFromCatalogs(skillKey);
|
|
26
|
+
const ins = resolved.instructionsText ?? "";
|
|
27
|
+
const pr = resolved.promptText ?? "";
|
|
42
28
|
const out = {
|
|
43
|
-
skillKey:
|
|
29
|
+
skillKey: resolved.subSkillKey ?? resolved.skillKey,
|
|
44
30
|
catalogItemId,
|
|
45
|
-
status:
|
|
46
|
-
title:
|
|
47
|
-
description:
|
|
48
|
-
isLocal:
|
|
31
|
+
status: resolved.status,
|
|
32
|
+
title: resolved.title || catalogItemId,
|
|
33
|
+
description: resolved.description,
|
|
34
|
+
isLocal: false,
|
|
49
35
|
instructionsMarkdown: ins ? toPresentationMarkdown(ins) : "",
|
|
50
36
|
promptMarkdown: pr ? toPresentationMarkdown(pr) : "",
|
|
37
|
+
...(resolved.parentSkillKey ? { parentSkillKey: resolved.parentSkillKey } : {}),
|
|
51
38
|
};
|
|
52
39
|
if (options.includeAudit === true) {
|
|
53
|
-
const ains =
|
|
54
|
-
const apr =
|
|
40
|
+
const ains = resolved.auditInstructionsText ?? "";
|
|
41
|
+
const apr = resolved.auditPromptText ?? "";
|
|
55
42
|
if (ains)
|
|
56
43
|
out.auditInstructionsMarkdown = toPresentationMarkdown(ains);
|
|
57
44
|
if (apr)
|
|
@@ -59,174 +46,173 @@ export async function getSkillTemplatesForPresentation(catalox, context, skillKe
|
|
|
59
46
|
}
|
|
60
47
|
return out;
|
|
61
48
|
}
|
|
62
|
-
async function
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
49
|
+
async function isSubSkillItem(itemId) {
|
|
50
|
+
const sub = await getNativeCatalogRecord(AI_SUB_SKILLS_CATALOG_ID, itemId);
|
|
51
|
+
return sub != null;
|
|
52
|
+
}
|
|
53
|
+
/** Whether a catalog item id resolves to an ai-sub-skills row. */
|
|
54
|
+
export async function isSubSkillCatalogItem(itemId) {
|
|
55
|
+
return isSubSkillItem(itemId);
|
|
56
|
+
}
|
|
57
|
+
async function writeBaseSkillRecord(input) {
|
|
58
|
+
const existing = await getNativeCatalogRecord(AI_SKILLS_CATALOG_ID, input.itemId);
|
|
59
|
+
const record = buildAiSkillsBaseWriteRecord({
|
|
60
|
+
itemId: input.itemId,
|
|
61
|
+
catalogId: AI_SKILLS_CATALOG_ID,
|
|
62
|
+
status: input.status,
|
|
63
|
+
title: input.title,
|
|
64
|
+
description: input.description,
|
|
65
|
+
instructionsText: input.instructionsText,
|
|
66
|
+
promptText: input.promptText,
|
|
67
|
+
auditInstructionsText: input.auditInstructionsText,
|
|
68
|
+
auditPromptText: input.auditPromptText,
|
|
69
|
+
optimixer: input.optimixer,
|
|
70
|
+
existing,
|
|
71
|
+
});
|
|
72
|
+
await replaceNativeCatalogRecord(AI_SKILLS_CATALOG_ID, record);
|
|
73
|
+
}
|
|
74
|
+
async function writeSubSkillRecord(input) {
|
|
75
|
+
const existing = await getNativeCatalogRecord(AI_SUB_SKILLS_CATALOG_ID, input.itemId);
|
|
76
|
+
const record = buildAiSubSkillsWriteRecord({
|
|
77
|
+
itemId: input.itemId,
|
|
78
|
+
catalogId: AI_SUB_SKILLS_CATALOG_ID,
|
|
79
|
+
parentSkillKey: input.parentSkillKey,
|
|
80
|
+
status: input.status,
|
|
81
|
+
overrides: input.overrides,
|
|
82
|
+
existing,
|
|
83
|
+
});
|
|
84
|
+
await replaceNativeCatalogRecord(AI_SUB_SKILLS_CATALOG_ID, record);
|
|
72
85
|
}
|
|
73
|
-
/**
|
|
74
|
-
* Template bodies as `{ role, content }[]` (presentation markdown). Always four entries in stable order.
|
|
75
|
-
*/
|
|
76
86
|
export async function getSkillContent(catalox, context, skillKey) {
|
|
77
|
-
|
|
87
|
+
void catalox;
|
|
88
|
+
void context;
|
|
89
|
+
const resolved = await resolveSkillRuntimeFromCatalogs(skillKey);
|
|
78
90
|
return SKILL_TEMPLATE_ROLES_ORDER.map((role) => {
|
|
79
91
|
const raw = role === "instructions"
|
|
80
|
-
?
|
|
92
|
+
? resolved.instructionsText ?? ""
|
|
81
93
|
: role === "prompt"
|
|
82
|
-
?
|
|
94
|
+
? resolved.promptText ?? ""
|
|
83
95
|
: role === "auditInstructions"
|
|
84
|
-
?
|
|
85
|
-
:
|
|
96
|
+
? resolved.auditInstructionsText ?? ""
|
|
97
|
+
: resolved.auditPromptText ?? "";
|
|
86
98
|
return { role, content: raw ? toPresentationMarkdown(raw) : "" };
|
|
87
99
|
});
|
|
88
100
|
}
|
|
89
|
-
/**
|
|
90
|
-
* Unique `{{token}}` names across all template bodies (same presentation strings as {@link getSkillContent}).
|
|
91
|
-
*/
|
|
92
101
|
export async function getSkillTokens(catalox, context, skillKey) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
return raw ? toPresentationMarkdown(raw) : "";
|
|
103
|
-
});
|
|
102
|
+
void catalox;
|
|
103
|
+
void context;
|
|
104
|
+
const resolved = await resolveSkillRuntimeFromCatalogs(skillKey);
|
|
105
|
+
const contents = [
|
|
106
|
+
resolved.instructionsText ?? "",
|
|
107
|
+
resolved.promptText ?? "",
|
|
108
|
+
resolved.auditInstructionsText ?? "",
|
|
109
|
+
resolved.auditPromptText ?? "",
|
|
110
|
+
].map((raw) => (raw ? toPresentationMarkdown(raw) : ""));
|
|
104
111
|
return extractTokenNamesFromStrings(contents);
|
|
105
112
|
}
|
|
106
|
-
/**
|
|
107
|
-
* Partial template update by role. Returns structured success/failure (including Catalox/not-found errors).
|
|
108
|
-
*/
|
|
109
113
|
export async function modifySkillContent(catalox, context, skillKey, parts, options) {
|
|
110
114
|
try {
|
|
111
115
|
if (parts.length === 0) {
|
|
112
|
-
return {
|
|
113
|
-
success: false,
|
|
114
|
-
error: "[AI-SKILLS] modifySkillContent: parts must include at least one role.",
|
|
115
|
-
};
|
|
116
|
+
return { success: false, error: "[AI-SKILLS] modifySkillContent: parts must include at least one role." };
|
|
116
117
|
}
|
|
117
118
|
const seen = new Set();
|
|
118
119
|
const patch = {};
|
|
119
120
|
for (const p of parts) {
|
|
120
121
|
if (!isSkillTemplateRole(p.role)) {
|
|
121
|
-
return {
|
|
122
|
-
success: false,
|
|
123
|
-
error: `[AI-SKILLS] modifySkillContent: unknown role "${String(p.role)}".`,
|
|
124
|
-
};
|
|
122
|
+
return { success: false, error: `[AI-SKILLS] modifySkillContent: unknown role "${String(p.role)}".` };
|
|
125
123
|
}
|
|
126
124
|
if (seen.has(p.role)) {
|
|
127
|
-
return {
|
|
128
|
-
success: false,
|
|
129
|
-
error: `[AI-SKILLS] modifySkillContent: duplicate role "${p.role}".`,
|
|
130
|
-
};
|
|
125
|
+
return { success: false, error: `[AI-SKILLS] modifySkillContent: duplicate role "${p.role}".` };
|
|
131
126
|
}
|
|
132
127
|
seen.add(p.role);
|
|
133
|
-
if (p.role === "instructions")
|
|
128
|
+
if (p.role === "instructions")
|
|
134
129
|
patch.instructionsMarkdown = p.content;
|
|
135
|
-
|
|
136
|
-
else if (p.role === "prompt") {
|
|
130
|
+
else if (p.role === "prompt")
|
|
137
131
|
patch.promptMarkdown = p.content;
|
|
138
|
-
|
|
139
|
-
else if (p.role === "auditInstructions") {
|
|
132
|
+
else if (p.role === "auditInstructions")
|
|
140
133
|
patch.auditInstructionsMarkdown = p.content;
|
|
141
|
-
|
|
142
|
-
else {
|
|
134
|
+
else
|
|
143
135
|
patch.auditPromptMarkdown = p.content;
|
|
144
|
-
}
|
|
145
136
|
}
|
|
146
137
|
await updateSkillTemplatesFromPresentation(catalox, context, skillKey, patch, options);
|
|
147
138
|
return { success: true };
|
|
148
139
|
}
|
|
149
140
|
catch (e) {
|
|
150
|
-
|
|
151
|
-
return { success: false, error: msg };
|
|
141
|
+
return { success: false, error: e instanceof Error ? e.message : String(e) };
|
|
152
142
|
}
|
|
153
143
|
}
|
|
154
|
-
/**
|
|
155
|
-
* Merges edited markdown into the native catalog item and upserts the full row.
|
|
156
|
-
* Requires Catalox **write** access (e.g. god-mode or app binding with write).
|
|
157
|
-
*
|
|
158
|
-
* @throws CataloxSkillNotFoundError when the item does not exist.
|
|
159
|
-
*/
|
|
160
144
|
export async function updateSkillTemplatesFromPresentation(catalox, context, skillKey, patch, options) {
|
|
145
|
+
void catalox;
|
|
146
|
+
void context;
|
|
161
147
|
const keys = Object.keys(patch).filter((k) => patch[k] !== undefined);
|
|
162
148
|
if (keys.length === 0) {
|
|
163
149
|
throw new Error("[AI-SKILLS] updateSkillTemplatesFromPresentation: patch must include at least one field.");
|
|
164
150
|
}
|
|
165
151
|
const catalogItemId = catalogItemIdFromSkillKey(skillKey);
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
173
|
-
const data = (res.item.data ?? {});
|
|
174
|
-
let instructionsText = asString(data.instructionsText);
|
|
175
|
-
let promptText = asString(data.promptText);
|
|
176
|
-
let auditInstructionsText = asString(data.auditInstructionsText);
|
|
177
|
-
let auditPromptText = asString(data.auditPromptText);
|
|
178
|
-
if (patch.instructionsMarkdown !== undefined) {
|
|
152
|
+
const resolved = await resolveSkillRuntimeFromCatalogs(skillKey);
|
|
153
|
+
let instructionsText = resolved.instructionsText ?? "";
|
|
154
|
+
let promptText = resolved.promptText ?? "";
|
|
155
|
+
let auditInstructionsText = resolved.auditInstructionsText ?? "";
|
|
156
|
+
let auditPromptText = resolved.auditPromptText ?? "";
|
|
157
|
+
if (patch.instructionsMarkdown !== undefined)
|
|
179
158
|
instructionsText = normalizeForStorage(patch.instructionsMarkdown);
|
|
180
|
-
|
|
181
|
-
if (patch.promptMarkdown !== undefined) {
|
|
159
|
+
if (patch.promptMarkdown !== undefined)
|
|
182
160
|
promptText = normalizeForStorage(patch.promptMarkdown);
|
|
183
|
-
}
|
|
184
161
|
if (patch.auditInstructionsMarkdown !== undefined) {
|
|
185
162
|
auditInstructionsText = normalizeForStorage(patch.auditInstructionsMarkdown);
|
|
186
163
|
}
|
|
187
|
-
if (patch.auditPromptMarkdown !== undefined)
|
|
164
|
+
if (patch.auditPromptMarkdown !== undefined)
|
|
188
165
|
auditPromptText = normalizeForStorage(patch.auditPromptMarkdown);
|
|
189
|
-
}
|
|
190
|
-
const prevStatus = asSkillCatalogStatus(data.status);
|
|
191
166
|
const catalogReleaseStatus = options?.catalogReleaseStatus !== undefined
|
|
192
167
|
? options.catalogReleaseStatus
|
|
193
|
-
:
|
|
168
|
+
: resolved.status === "published"
|
|
194
169
|
? "published"
|
|
195
170
|
: undefined;
|
|
196
171
|
const status = computeSkillRowStatus(instructionsText || undefined, promptText || undefined, catalogReleaseStatus);
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
172
|
+
if (resolved.parentSkillKey) {
|
|
173
|
+
const parentRecord = await getNativeCatalogRecord(AI_SKILLS_CATALOG_ID, resolved.parentSkillKey);
|
|
174
|
+
if (!parentRecord) {
|
|
175
|
+
throw new CataloxSkillNotFoundError(skillKey, resolved.parentSkillKey);
|
|
176
|
+
}
|
|
177
|
+
const parent = resolveBaseSkillFromRecord(parentRecord, `skills/${resolved.parentSkillKey}`);
|
|
178
|
+
const nextRuntime = {
|
|
179
|
+
...parent,
|
|
180
|
+
skillKey: catalogItemId,
|
|
181
|
+
subSkillKey: catalogItemId,
|
|
182
|
+
parentSkillKey: resolved.parentSkillKey,
|
|
183
|
+
status,
|
|
184
|
+
instructionsText,
|
|
185
|
+
promptText,
|
|
186
|
+
auditInstructionsText,
|
|
187
|
+
auditPromptText,
|
|
188
|
+
};
|
|
189
|
+
const overrides = computeSubSkillOverrides(parent, nextRuntime);
|
|
190
|
+
await writeSubSkillRecord({
|
|
191
|
+
itemId: catalogItemId,
|
|
192
|
+
parentSkillKey: resolved.parentSkillKey,
|
|
193
|
+
status,
|
|
194
|
+
overrides,
|
|
195
|
+
});
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
await writeBaseSkillRecord({
|
|
199
|
+
itemId: catalogItemId,
|
|
203
200
|
status,
|
|
201
|
+
title: resolved.title || catalogItemId,
|
|
202
|
+
description: resolved.description,
|
|
204
203
|
instructionsText,
|
|
205
204
|
promptText,
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
210
|
-
if (auditPromptText.length > 0 || patch.auditPromptMarkdown !== undefined) {
|
|
211
|
-
payload.auditPromptText = auditPromptText;
|
|
212
|
-
}
|
|
213
|
-
appendParentSkillKeyIfPresent(data, payload);
|
|
214
|
-
await catalox.batchUpsertNativeCatalogItems(context, AI_SKILLS_CATALOG_ID, [payload]);
|
|
205
|
+
auditInstructionsText,
|
|
206
|
+
auditPromptText,
|
|
207
|
+
optimixer: resolved.optimixer,
|
|
208
|
+
});
|
|
215
209
|
}
|
|
216
|
-
/**
|
|
217
|
-
* Creates or updates a full skill catalog row (metadata + optional template markdown).
|
|
218
|
-
* Uses read–merge–write when the item exists; otherwise writes a new row.
|
|
219
|
-
* Requires Catalox **write** access.
|
|
220
|
-
*
|
|
221
|
-
* @throws CataloxSkillAlreadyExistsError when `options.ifNotExists` is true and the item exists.
|
|
222
|
-
*/
|
|
223
210
|
export async function upsertSkillCatalogItem(catalox, context, input, options) {
|
|
211
|
+
void catalox;
|
|
212
|
+
void context;
|
|
224
213
|
const catalogItemId = catalogItemIdFromSkillKey(input.skillKey);
|
|
225
|
-
const
|
|
226
|
-
if (
|
|
227
|
-
throw new Error(`[AI-SKILLS] Catalox mapping blocked for skill ${catalogItemId}`);
|
|
228
|
-
}
|
|
229
|
-
if (options?.ifNotExists === true && res.outcome === "found") {
|
|
214
|
+
const existing = await getNativeCatalogRecord(AI_SKILLS_CATALOG_ID, catalogItemId);
|
|
215
|
+
if (options?.ifNotExists === true && existing) {
|
|
230
216
|
throw new CataloxSkillAlreadyExistsError(input.skillKey, catalogItemId);
|
|
231
217
|
}
|
|
232
218
|
let instructionsText = "";
|
|
@@ -234,248 +220,221 @@ export async function upsertSkillCatalogItem(catalox, context, input, options) {
|
|
|
234
220
|
let auditInstructionsText = "";
|
|
235
221
|
let auditPromptText = "";
|
|
236
222
|
let prevStatus = "planned";
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
223
|
+
let optimixer = input.optimixer ?? defaultSkillOptimixerCatalogSpecForTests();
|
|
224
|
+
if (existing) {
|
|
225
|
+
const resolved = resolveBaseSkillFromRecord(existing, input.skillKey);
|
|
226
|
+
prevStatus = resolved.status;
|
|
227
|
+
instructionsText = resolved.instructionsText ?? "";
|
|
228
|
+
promptText = resolved.promptText ?? "";
|
|
229
|
+
auditInstructionsText = resolved.auditInstructionsText ?? "";
|
|
230
|
+
auditPromptText = resolved.auditPromptText ?? "";
|
|
231
|
+
if (input.optimixer === undefined)
|
|
232
|
+
optimixer = resolved.optimixer;
|
|
233
|
+
}
|
|
234
|
+
if (input.instructionsMarkdown !== undefined)
|
|
246
235
|
instructionsText = normalizeForStorage(input.instructionsMarkdown);
|
|
247
|
-
|
|
248
|
-
if (input.promptMarkdown !== undefined) {
|
|
236
|
+
if (input.promptMarkdown !== undefined)
|
|
249
237
|
promptText = normalizeForStorage(input.promptMarkdown);
|
|
250
|
-
}
|
|
251
238
|
if (input.auditInstructionsMarkdown !== undefined) {
|
|
252
239
|
auditInstructionsText = normalizeForStorage(input.auditInstructionsMarkdown);
|
|
253
240
|
}
|
|
254
|
-
if (input.auditPromptMarkdown !== undefined)
|
|
241
|
+
if (input.auditPromptMarkdown !== undefined)
|
|
255
242
|
auditPromptText = normalizeForStorage(input.auditPromptMarkdown);
|
|
256
|
-
}
|
|
257
|
-
const shortKey = res.outcome === "found"
|
|
258
|
-
? asString((res.item.data ?? {}).skillKey) || catalogItemId
|
|
259
|
-
: catalogItemId;
|
|
260
243
|
const catalogReleaseStatus = input.catalogReleaseStatus !== undefined
|
|
261
244
|
? input.catalogReleaseStatus
|
|
262
245
|
: prevStatus === "published"
|
|
263
246
|
? "published"
|
|
264
247
|
: undefined;
|
|
265
248
|
const status = computeSkillRowStatus(instructionsText || undefined, promptText || undefined, catalogReleaseStatus);
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
title: input.title || shortKey,
|
|
269
|
-
description: input.description,
|
|
270
|
-
isLocal: input.isLocal,
|
|
249
|
+
await writeBaseSkillRecord({
|
|
250
|
+
itemId: catalogItemId,
|
|
271
251
|
status,
|
|
252
|
+
title: input.title || catalogItemId,
|
|
253
|
+
description: input.description,
|
|
272
254
|
instructionsText,
|
|
273
255
|
promptText,
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
else {
|
|
288
|
-
throw new Error(`[AI-SKILLS] upsertSkillCatalogItem("${input.skillKey}") requires optimixer on new catalog rows (Optimixer v3 mandatory fields).`);
|
|
256
|
+
auditInstructionsText,
|
|
257
|
+
auditPromptText,
|
|
258
|
+
optimixer,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
export async function updateSkillMetadata(catalox, context, input) {
|
|
262
|
+
void catalox;
|
|
263
|
+
void context;
|
|
264
|
+
const keys = ["title", "description", "optimixer", "catalogReleaseStatus"];
|
|
265
|
+
const hasPatch = keys.some((k) => input[k] !== undefined);
|
|
266
|
+
if (!hasPatch) {
|
|
267
|
+
throw new Error("[AI-SKILLS] updateSkillMetadata: patch must include at least one field.");
|
|
289
268
|
}
|
|
290
|
-
|
|
291
|
-
|
|
269
|
+
const catalogItemId = catalogItemIdFromSkillKey(input.skillKey);
|
|
270
|
+
const resolved = await resolveSkillRuntimeFromCatalogs(input.skillKey);
|
|
271
|
+
const title = input.title !== undefined ? input.title : resolved.title || catalogItemId;
|
|
272
|
+
const description = input.description !== undefined ? input.description : resolved.description;
|
|
273
|
+
const optimixer = input.optimixer !== undefined ? input.optimixer : resolved.optimixer;
|
|
274
|
+
const catalogReleaseStatus = input.catalogReleaseStatus !== undefined
|
|
275
|
+
? input.catalogReleaseStatus
|
|
276
|
+
: resolved.status === "published"
|
|
277
|
+
? "published"
|
|
278
|
+
: undefined;
|
|
279
|
+
const status = computeSkillRowStatus(resolved.instructionsText || undefined, resolved.promptText || undefined, catalogReleaseStatus);
|
|
280
|
+
if (resolved.parentSkillKey) {
|
|
281
|
+
const parentRecord = await getNativeCatalogRecord(AI_SKILLS_CATALOG_ID, resolved.parentSkillKey);
|
|
282
|
+
if (!parentRecord) {
|
|
283
|
+
throw new CataloxSkillNotFoundError(input.skillKey, resolved.parentSkillKey);
|
|
284
|
+
}
|
|
285
|
+
const parent = resolveBaseSkillFromRecord(parentRecord, `skills/${resolved.parentSkillKey}`);
|
|
286
|
+
const nextRuntime = {
|
|
287
|
+
...parent,
|
|
288
|
+
skillKey: catalogItemId,
|
|
289
|
+
subSkillKey: catalogItemId,
|
|
290
|
+
parentSkillKey: resolved.parentSkillKey,
|
|
291
|
+
status,
|
|
292
|
+
title,
|
|
293
|
+
description,
|
|
294
|
+
instructionsText: resolved.instructionsText,
|
|
295
|
+
promptText: resolved.promptText,
|
|
296
|
+
auditInstructionsText: resolved.auditInstructionsText,
|
|
297
|
+
auditPromptText: resolved.auditPromptText,
|
|
298
|
+
optimixer,
|
|
299
|
+
};
|
|
300
|
+
const overrides = computeSubSkillOverrides(parent, nextRuntime);
|
|
301
|
+
await writeSubSkillRecord({
|
|
302
|
+
itemId: catalogItemId,
|
|
303
|
+
parentSkillKey: resolved.parentSkillKey,
|
|
304
|
+
status,
|
|
305
|
+
overrides,
|
|
306
|
+
});
|
|
307
|
+
return;
|
|
292
308
|
}
|
|
293
|
-
await
|
|
309
|
+
await writeBaseSkillRecord({
|
|
310
|
+
itemId: catalogItemId,
|
|
311
|
+
status,
|
|
312
|
+
title,
|
|
313
|
+
description,
|
|
314
|
+
instructionsText: resolved.instructionsText ?? "",
|
|
315
|
+
promptText: resolved.promptText ?? "",
|
|
316
|
+
auditInstructionsText: resolved.auditInstructionsText ?? "",
|
|
317
|
+
auditPromptText: resolved.auditPromptText ?? "",
|
|
318
|
+
optimixer,
|
|
319
|
+
});
|
|
294
320
|
}
|
|
295
|
-
/**
|
|
296
|
-
* Soft-deletes a skill: clears template bodies and audit fields and sets status to `planned`.
|
|
297
|
-
* Requires Catalox **write** access.
|
|
298
|
-
*
|
|
299
|
-
* @throws CataloxSkillNotFoundError when the item does not exist.
|
|
300
|
-
*/
|
|
301
321
|
export async function softDeleteSkillCatalogItem(catalox, context, skillKey) {
|
|
322
|
+
void catalox;
|
|
323
|
+
void context;
|
|
302
324
|
const catalogItemId = catalogItemIdFromSkillKey(skillKey);
|
|
303
|
-
|
|
304
|
-
|
|
325
|
+
if (await isSubSkillItem(catalogItemId)) {
|
|
326
|
+
const sub = await getNativeCatalogRecord(AI_SUB_SKILLS_CATALOG_ID, catalogItemId);
|
|
327
|
+
if (!sub)
|
|
328
|
+
throw new CataloxSkillNotFoundError(skillKey, catalogItemId);
|
|
329
|
+
const parentKey = readIndexedParentSkillKey(sub);
|
|
330
|
+
await writeSubSkillRecord({
|
|
331
|
+
itemId: catalogItemId,
|
|
332
|
+
parentSkillKey: parentKey,
|
|
333
|
+
status: "planned",
|
|
334
|
+
overrides: {},
|
|
335
|
+
});
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
const existing = await getNativeCatalogRecord(AI_SKILLS_CATALOG_ID, catalogItemId);
|
|
339
|
+
if (!existing)
|
|
305
340
|
throw new CataloxSkillNotFoundError(skillKey, catalogItemId);
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
const isLocal = data.isLocal === true;
|
|
315
|
-
const instructionsText = "";
|
|
316
|
-
const promptText = "";
|
|
317
|
-
const status = computeSkillRowStatus(undefined, undefined, undefined);
|
|
318
|
-
const payload = {
|
|
319
|
-
skillKey: shortKey,
|
|
320
|
-
title,
|
|
321
|
-
description,
|
|
322
|
-
isLocal,
|
|
323
|
-
status,
|
|
324
|
-
instructionsText,
|
|
325
|
-
promptText,
|
|
341
|
+
const resolved = resolveBaseSkillFromRecord(existing, skillKey);
|
|
342
|
+
await writeBaseSkillRecord({
|
|
343
|
+
itemId: catalogItemId,
|
|
344
|
+
status: "planned",
|
|
345
|
+
title: resolved.title,
|
|
346
|
+
description: resolved.description,
|
|
347
|
+
instructionsText: "",
|
|
348
|
+
promptText: "",
|
|
326
349
|
auditInstructionsText: "",
|
|
327
350
|
auditPromptText: "",
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
await catalox.batchUpsertNativeCatalogItems(context, AI_SKILLS_CATALOG_ID, [payload]);
|
|
351
|
+
optimixer: resolved.optimixer,
|
|
352
|
+
});
|
|
331
353
|
}
|
|
332
|
-
/**
|
|
333
|
-
* Duplicates a catalog skill into a new key, marking it with `parentSkillKey`. Structured success/failure.
|
|
334
|
-
*/
|
|
335
354
|
export async function createSubSkill(catalox, context, input) {
|
|
355
|
+
void catalox;
|
|
356
|
+
void context;
|
|
336
357
|
try {
|
|
337
358
|
const sourceItemId = catalogItemIdFromSkillKey(input.sourceSkillKey);
|
|
338
359
|
const newItemId = catalogItemIdFromSkillKey(input.newSkillKey);
|
|
339
360
|
if (sourceItemId === newItemId) {
|
|
340
|
-
return {
|
|
341
|
-
success: false,
|
|
342
|
-
error: "[AI-SKILLS] createSubSkill: sourceSkillKey and newSkillKey must differ.",
|
|
343
|
-
};
|
|
344
|
-
}
|
|
345
|
-
const srcRes = await catalox.getCatalogItem(context, AI_SKILLS_CATALOG_ID, sourceItemId);
|
|
346
|
-
if (srcRes.outcome === "not_found") {
|
|
347
|
-
return {
|
|
348
|
-
success: false,
|
|
349
|
-
error: `[AI-SKILLS] createSubSkill: source skill not found (${input.sourceSkillKey}).`,
|
|
350
|
-
};
|
|
361
|
+
return { success: false, error: "[AI-SKILLS] createSubSkill: sourceSkillKey and newSkillKey must differ." };
|
|
351
362
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
error: `[AI-SKILLS] Catalox mapping blocked for skill ${sourceItemId}`,
|
|
356
|
-
};
|
|
363
|
+
const parentRecord = await getNativeCatalogRecord(AI_SKILLS_CATALOG_ID, sourceItemId);
|
|
364
|
+
if (!parentRecord) {
|
|
365
|
+
return { success: false, error: `[AI-SKILLS] createSubSkill: source skill not found (${input.sourceSkillKey}).` };
|
|
357
366
|
}
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
error: `[AI-SKILLS] Catalox mapping blocked for skill ${newItemId}`,
|
|
363
|
-
};
|
|
367
|
+
const parent = resolveBaseSkillFromRecord(parentRecord, input.sourceSkillKey);
|
|
368
|
+
const existingSub = await getNativeCatalogRecord(AI_SUB_SKILLS_CATALOG_ID, newItemId);
|
|
369
|
+
if (existingSub) {
|
|
370
|
+
return { success: false, error: `[AI-SKILLS] createSubSkill: target skill already exists (${input.newSkillKey}).` };
|
|
364
371
|
}
|
|
365
|
-
if (tgtRes.outcome === "found") {
|
|
366
|
-
return {
|
|
367
|
-
success: false,
|
|
368
|
-
error: `[AI-SKILLS] createSubSkill: target skill already exists (${input.newSkillKey}).`,
|
|
369
|
-
};
|
|
370
|
-
}
|
|
371
|
-
const sourceData = (srcRes.item.data ?? {});
|
|
372
|
-
const parentShortKey = asString(sourceData.skillKey) || sourceItemId;
|
|
373
372
|
const ov = input.overrides ?? {};
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
const prevStatus = asSkillCatalogStatus(sourceData.status);
|
|
373
|
+
const childRuntime = {
|
|
374
|
+
...parent,
|
|
375
|
+
skillKey: newItemId,
|
|
376
|
+
subSkillKey: newItemId,
|
|
377
|
+
parentSkillKey: sourceItemId,
|
|
378
|
+
status: parent.status,
|
|
379
|
+
title: ov.title !== undefined ? ov.title : parent.title,
|
|
380
|
+
description: ov.description !== undefined ? ov.description : parent.description,
|
|
381
|
+
instructionsText: ov.instructionsMarkdown !== undefined
|
|
382
|
+
? normalizeForStorage(ov.instructionsMarkdown)
|
|
383
|
+
: parent.instructionsText,
|
|
384
|
+
promptText: ov.promptMarkdown !== undefined ? normalizeForStorage(ov.promptMarkdown) : parent.promptText,
|
|
385
|
+
auditInstructionsText: ov.auditInstructionsMarkdown !== undefined
|
|
386
|
+
? normalizeForStorage(ov.auditInstructionsMarkdown)
|
|
387
|
+
: parent.auditInstructionsText,
|
|
388
|
+
auditPromptText: ov.auditPromptMarkdown !== undefined
|
|
389
|
+
? normalizeForStorage(ov.auditPromptMarkdown)
|
|
390
|
+
: parent.auditPromptText,
|
|
391
|
+
optimixer: ov.optimixer ?? parent.optimixer,
|
|
392
|
+
};
|
|
395
393
|
const catalogReleaseStatus = ov.catalogReleaseStatus !== undefined
|
|
396
394
|
? ov.catalogReleaseStatus
|
|
397
|
-
:
|
|
395
|
+
: parent.status === "published"
|
|
398
396
|
? "published"
|
|
399
397
|
: undefined;
|
|
400
|
-
const status = computeSkillRowStatus(instructionsText
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
isLocal,
|
|
398
|
+
const status = computeSkillRowStatus(childRuntime.instructionsText, childRuntime.promptText, catalogReleaseStatus);
|
|
399
|
+
childRuntime.status = status;
|
|
400
|
+
const overrides = computeSubSkillOverrides(parent, childRuntime);
|
|
401
|
+
await writeSubSkillRecord({
|
|
402
|
+
itemId: newItemId,
|
|
403
|
+
parentSkillKey: sourceItemId,
|
|
407
404
|
status,
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
};
|
|
411
|
-
if (auditInstructionsText.length > 0 || ov.auditInstructionsMarkdown !== undefined) {
|
|
412
|
-
payload.auditInstructionsText = auditInstructionsText;
|
|
413
|
-
}
|
|
414
|
-
if (auditPromptText.length > 0 || ov.auditPromptMarkdown !== undefined) {
|
|
415
|
-
payload.auditPromptText = auditPromptText;
|
|
416
|
-
}
|
|
417
|
-
copySkillOptimixerCatalogDataFields(sourceData, payload);
|
|
418
|
-
await catalox.batchUpsertNativeCatalogItems(context, AI_SKILLS_CATALOG_ID, [payload]);
|
|
405
|
+
overrides,
|
|
406
|
+
});
|
|
419
407
|
return { success: true };
|
|
420
408
|
}
|
|
421
409
|
catch (e) {
|
|
422
|
-
|
|
423
|
-
return { success: false, error: msg };
|
|
410
|
+
return { success: false, error: e instanceof Error ? e.message : String(e) };
|
|
424
411
|
}
|
|
425
412
|
}
|
|
426
|
-
/**
|
|
427
|
-
* Deletes a native catalog row only when it is a sub-skill (`parentSkillKey` set).
|
|
428
|
-
*/
|
|
429
413
|
export async function deleteSubSkill(catalox, context, subSkillKey) {
|
|
414
|
+
void catalox;
|
|
415
|
+
void context;
|
|
430
416
|
try {
|
|
431
417
|
const catalogItemId = catalogItemIdFromSkillKey(subSkillKey);
|
|
432
|
-
const
|
|
433
|
-
if (
|
|
434
|
-
return {
|
|
435
|
-
success: false,
|
|
436
|
-
error: `[AI-SKILLS] deleteSubSkill: skill not found (${subSkillKey}).`,
|
|
437
|
-
};
|
|
418
|
+
const sub = await getNativeCatalogRecord(AI_SUB_SKILLS_CATALOG_ID, catalogItemId);
|
|
419
|
+
if (!sub) {
|
|
420
|
+
return { success: false, error: `[AI-SKILLS] deleteSubSkill: skill not found (${subSkillKey}).` };
|
|
438
421
|
}
|
|
439
|
-
|
|
440
|
-
return {
|
|
441
|
-
success: false,
|
|
442
|
-
error: `[AI-SKILLS] Catalox mapping blocked for skill ${catalogItemId}`,
|
|
443
|
-
};
|
|
444
|
-
}
|
|
445
|
-
const data = (res.item.data ?? {});
|
|
446
|
-
const parent = asString(data.parentSkillKey);
|
|
447
|
-
if (parent.length === 0) {
|
|
448
|
-
return {
|
|
449
|
-
success: false,
|
|
450
|
-
error: "[AI-SKILLS] deleteSubSkill: only sub-skills (rows with parentSkillKey) can be deleted.",
|
|
451
|
-
};
|
|
452
|
-
}
|
|
453
|
-
await catalox.deleteNativeCatalogItem(context, AI_SKILLS_CATALOG_ID, catalogItemId);
|
|
422
|
+
await deleteNativeCatalogRecordByItemId(AI_SUB_SKILLS_CATALOG_ID, catalogItemId, sub);
|
|
454
423
|
return { success: true };
|
|
455
424
|
}
|
|
456
425
|
catch (e) {
|
|
457
|
-
|
|
458
|
-
return { success: false, error: msg };
|
|
426
|
+
return { success: false, error: e instanceof Error ? e.message : String(e) };
|
|
459
427
|
}
|
|
460
428
|
}
|
|
461
|
-
/**
|
|
462
|
-
* Returns unique `{{token}}` names from raw Catalox template strings (before presentation transforms).
|
|
463
|
-
*/
|
|
464
429
|
export async function getSkillTemplateInputs(catalox, context, skillKey) {
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
throw new CataloxSkillNotFoundError(skillKey, catalogItemId);
|
|
469
|
-
}
|
|
470
|
-
if (res.outcome === "mapping_blocked") {
|
|
471
|
-
throw new Error(`[AI-SKILLS] Catalox mapping blocked for skill ${catalogItemId}`);
|
|
472
|
-
}
|
|
473
|
-
const data = (res.item.data ?? {});
|
|
430
|
+
void catalox;
|
|
431
|
+
void context;
|
|
432
|
+
const resolved = await resolveSkillRuntimeFromCatalogs(skillKey);
|
|
474
433
|
return extractTemplateTokensFromTexts({
|
|
475
|
-
instructionsText:
|
|
476
|
-
promptText:
|
|
477
|
-
auditInstructionsText:
|
|
478
|
-
auditPromptText:
|
|
434
|
+
instructionsText: resolved.instructionsText,
|
|
435
|
+
promptText: resolved.promptText,
|
|
436
|
+
auditInstructionsText: resolved.auditInstructionsText,
|
|
437
|
+
auditPromptText: resolved.auditPromptText,
|
|
479
438
|
});
|
|
480
439
|
}
|
|
481
440
|
//# sourceMappingURL=skill-template-catalog-mutations.js.map
|