@agenticmail/core 0.9.23 → 0.9.24
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.cjs +318 -23
- package/dist/index.d.cts +281 -1
- package/dist/index.d.ts +281 -1
- package/dist/index.js +309 -23
- package/dist/skills/built-in/airline-change-or-refund.json +111 -0
- package/dist/skills/built-in/book-medical-appointment.json +99 -0
- package/dist/skills/built-in/book-restaurant-reservation.json +93 -0
- package/dist/skills/built-in/cancel-subscription-graceful.json +101 -0
- package/dist/skills/built-in/court-administrative-checkin.json +99 -0
- package/dist/skills/built-in/dispute-credit-card-charge.json +105 -0
- package/dist/skills/built-in/handle-debt-collector.json +109 -0
- package/dist/skills/built-in/negotiate-bill-reduction.json +116 -0
- package/dist/skills/built-in/schedule-home-service.json +100 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -851,6 +851,7 @@ __export(index_exports, {
|
|
|
851
851
|
getTelegramWebhookInfo: () => getTelegramWebhookInfo,
|
|
852
852
|
hostSessionStoragePath: () => hostSessionStoragePath,
|
|
853
853
|
inferPhoneRegion: () => inferPhoneRegion,
|
|
854
|
+
invalidateSkillCache: () => invalidateSkillCache,
|
|
854
855
|
isInternalEmail: () => isInternalEmail,
|
|
855
856
|
isLoopbackMailHost: () => isLoopbackMailHost,
|
|
856
857
|
isOperatorReplySender: () => isOperatorReplySender,
|
|
@@ -859,7 +860,9 @@ __export(index_exports, {
|
|
|
859
860
|
isTelegramChatAllowed: () => isTelegramChatAllowed,
|
|
860
861
|
isTelegramStopCommand: () => isTelegramStopCommand,
|
|
861
862
|
isValidPhoneNumber: () => isValidPhoneNumber,
|
|
863
|
+
listSkills: () => listSkills,
|
|
862
864
|
loadHostSession: () => loadHostSession,
|
|
865
|
+
loadSkill: () => loadSkill,
|
|
863
866
|
mapProviderSmsStatus: () => mapProviderSmsStatus,
|
|
864
867
|
nextTelegramOffset: () => nextTelegramOffset,
|
|
865
868
|
normalizeAddress: () => normalizeAddress,
|
|
@@ -884,6 +887,7 @@ __export(index_exports, {
|
|
|
884
887
|
redactSecret: () => redactSecret,
|
|
885
888
|
redactSmsConfig: () => redactSmsConfig,
|
|
886
889
|
redactTelegramConfig: () => redactTelegramConfig,
|
|
890
|
+
renderSkillAsPrompt: () => renderSkillAsPrompt,
|
|
887
891
|
requireBinary: () => requireBinary,
|
|
888
892
|
requireWhisperModel: () => requireWhisperModel,
|
|
889
893
|
resolveConfig: () => resolveConfig,
|
|
@@ -892,8 +896,10 @@ __export(index_exports, {
|
|
|
892
896
|
sanitizeEmail: () => sanitizeEmail,
|
|
893
897
|
saveConfig: () => saveConfig,
|
|
894
898
|
saveHostSession: () => saveHostSession,
|
|
899
|
+
saveUserSkill: () => saveUserSkill,
|
|
895
900
|
scanOutboundEmail: () => scanOutboundEmail,
|
|
896
901
|
scoreEmail: () => scoreEmail,
|
|
902
|
+
searchSkills: () => searchSkills,
|
|
897
903
|
sendTelegramMessage: () => sendTelegramMessage,
|
|
898
904
|
setOperatorEmail: () => setOperatorEmail,
|
|
899
905
|
setTelegramWebhook: () => setTelegramWebhook,
|
|
@@ -906,10 +912,12 @@ __export(index_exports, {
|
|
|
906
912
|
threadIdFor: () => threadIdFor,
|
|
907
913
|
tokenize: () => tokenize,
|
|
908
914
|
tryJoin: () => tryJoin,
|
|
915
|
+
userSkillsDir: () => userSkillsDir,
|
|
909
916
|
validateApiUrl: () => validateApiUrl,
|
|
910
917
|
validatePhoneMissionPolicy: () => validatePhoneMissionPolicy,
|
|
911
918
|
validatePhoneMissionStart: () => validatePhoneMissionStart,
|
|
912
919
|
validatePhoneTransportProfile: () => validatePhoneTransportProfile,
|
|
920
|
+
validateSkill: () => validateSkill,
|
|
913
921
|
validateTwilioSignature: () => validateTwilioSignature,
|
|
914
922
|
webSearch: () => webSearch
|
|
915
923
|
});
|
|
@@ -2016,14 +2024,14 @@ var StalwartAdmin = class {
|
|
|
2016
2024
|
if (!isValidDomain(domain)) {
|
|
2017
2025
|
throw new Error(`Invalid domain format: "${domain}"`);
|
|
2018
2026
|
}
|
|
2019
|
-
const { readFileSync:
|
|
2020
|
-
const { homedir:
|
|
2021
|
-
const { join:
|
|
2022
|
-
const configPath =
|
|
2027
|
+
const { readFileSync: readFileSync11, writeFileSync: writeFileSync12 } = await import("fs");
|
|
2028
|
+
const { homedir: homedir14 } = await import("os");
|
|
2029
|
+
const { join: join17 } = await import("path");
|
|
2030
|
+
const configPath = join17(homedir14(), ".agenticmail", "stalwart.toml");
|
|
2023
2031
|
try {
|
|
2024
|
-
let config =
|
|
2032
|
+
let config = readFileSync11(configPath, "utf-8");
|
|
2025
2033
|
config = config.replace(/^hostname\s*=\s*"[^"]*"/m, `hostname = "${escapeTomlString(domain)}"`);
|
|
2026
|
-
|
|
2034
|
+
writeFileSync12(configPath, config);
|
|
2027
2035
|
console.log(`[Stalwart] Updated hostname to "${domain}" in stalwart.toml`);
|
|
2028
2036
|
} catch (err) {
|
|
2029
2037
|
throw new Error(`Failed to set config server.hostname=${domain}`);
|
|
@@ -2032,15 +2040,15 @@ var StalwartAdmin = class {
|
|
|
2032
2040
|
// --- DKIM ---
|
|
2033
2041
|
/** Path to the host-side stalwart.toml (mounted read-only into container) */
|
|
2034
2042
|
get configPath() {
|
|
2035
|
-
const { homedir:
|
|
2036
|
-
const { join:
|
|
2037
|
-
return
|
|
2043
|
+
const { homedir: homedir14 } = require("os");
|
|
2044
|
+
const { join: join17 } = require("path");
|
|
2045
|
+
return join17(homedir14(), ".agenticmail", "stalwart.toml");
|
|
2038
2046
|
}
|
|
2039
2047
|
/** Path to host-side DKIM key directory */
|
|
2040
2048
|
get dkimDir() {
|
|
2041
|
-
const { homedir:
|
|
2042
|
-
const { join:
|
|
2043
|
-
return
|
|
2049
|
+
const { homedir: homedir14 } = require("os");
|
|
2050
|
+
const { join: join17 } = require("path");
|
|
2051
|
+
return join17(homedir14(), ".agenticmail");
|
|
2044
2052
|
}
|
|
2045
2053
|
/**
|
|
2046
2054
|
* Create/reuse a DKIM signing key for a domain.
|
|
@@ -2141,12 +2149,12 @@ var StalwartAdmin = class {
|
|
|
2141
2149
|
* This bypasses the need for a PTR record on the sending IP.
|
|
2142
2150
|
*/
|
|
2143
2151
|
async configureOutboundRelay(config) {
|
|
2144
|
-
const { readFileSync:
|
|
2145
|
-
const { homedir:
|
|
2146
|
-
const { join:
|
|
2152
|
+
const { readFileSync: readFileSync11, writeFileSync: writeFileSync12 } = await import("fs");
|
|
2153
|
+
const { homedir: homedir14 } = await import("os");
|
|
2154
|
+
const { join: join17 } = await import("path");
|
|
2147
2155
|
const routeName = config.routeName ?? "gmail";
|
|
2148
|
-
const tomlPath =
|
|
2149
|
-
let toml =
|
|
2156
|
+
const tomlPath = join17(homedir14(), ".agenticmail", "stalwart.toml");
|
|
2157
|
+
let toml = readFileSync11(tomlPath, "utf-8");
|
|
2150
2158
|
toml = toml.replace(/\n\[queue\.route\.gmail\][\s\S]*?(?=\n\[|$)/, "");
|
|
2151
2159
|
toml = toml.replace(/\n\[queue\.strategy\][\s\S]*?(?=\n\[|$)/, "");
|
|
2152
2160
|
const safeRouteName = routeName.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
@@ -2166,7 +2174,7 @@ auth.secret = "${escapeTomlString(config.password)}"
|
|
|
2166
2174
|
route = [ { if = "is_local_domain('', rcpt_domain)", then = "'local'" },
|
|
2167
2175
|
{ else = "'${safeRouteName}'" } ]
|
|
2168
2176
|
`;
|
|
2169
|
-
|
|
2177
|
+
writeFileSync12(tomlPath, toml, "utf-8");
|
|
2170
2178
|
await this.restartContainer();
|
|
2171
2179
|
}
|
|
2172
2180
|
};
|
|
@@ -8372,12 +8380,12 @@ var GatewayManager = class {
|
|
|
8372
8380
|
zone = await this.cfClient.createZone(domain);
|
|
8373
8381
|
}
|
|
8374
8382
|
const existingRecords = await this.cfClient.listDnsRecords(zone.id);
|
|
8375
|
-
const { homedir:
|
|
8376
|
-
const backupDir = (0, import_node_path4.join)(
|
|
8383
|
+
const { homedir: homedir14 } = await import("os");
|
|
8384
|
+
const backupDir = (0, import_node_path4.join)(homedir14(), ".agenticmail");
|
|
8377
8385
|
const backupPath = (0, import_node_path4.join)(backupDir, `dns-backup-${domain}-${Date.now()}.json`);
|
|
8378
|
-
const { writeFileSync:
|
|
8379
|
-
|
|
8380
|
-
|
|
8386
|
+
const { writeFileSync: writeFileSync12, mkdirSync: mkdirSync13 } = await import("fs");
|
|
8387
|
+
mkdirSync13(backupDir, { recursive: true });
|
|
8388
|
+
writeFileSync12(backupPath, JSON.stringify({
|
|
8381
8389
|
domain,
|
|
8382
8390
|
zoneId: zone.id,
|
|
8383
8391
|
backedUpAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -14763,6 +14771,285 @@ var AgentMemoryManager = class {
|
|
|
14763
14771
|
};
|
|
14764
14772
|
}
|
|
14765
14773
|
};
|
|
14774
|
+
|
|
14775
|
+
// src/skills/registry.ts
|
|
14776
|
+
var import_node_fs14 = require("fs");
|
|
14777
|
+
var import_node_path15 = require("path");
|
|
14778
|
+
var import_node_url = require("url");
|
|
14779
|
+
var import_node_os12 = require("os");
|
|
14780
|
+
var import_meta4 = {};
|
|
14781
|
+
function builtInDir() {
|
|
14782
|
+
const here = (0, import_node_path15.dirname)((0, import_node_url.fileURLToPath)(import_meta4.url));
|
|
14783
|
+
return (0, import_node_path15.join)(here, "built-in");
|
|
14784
|
+
}
|
|
14785
|
+
function userDir() {
|
|
14786
|
+
const dir2 = (0, import_node_path15.join)((0, import_node_os12.homedir)(), ".agenticmail", "skills");
|
|
14787
|
+
try {
|
|
14788
|
+
if (!(0, import_node_fs14.existsSync)(dir2)) (0, import_node_fs14.mkdirSync)(dir2, { recursive: true });
|
|
14789
|
+
} catch {
|
|
14790
|
+
}
|
|
14791
|
+
return dir2;
|
|
14792
|
+
}
|
|
14793
|
+
var cache = { ts: 0, byId: null };
|
|
14794
|
+
var CACHE_TTL_MS = 5e3;
|
|
14795
|
+
function loadAllSkillsFromDisk() {
|
|
14796
|
+
const all = /* @__PURE__ */ new Map();
|
|
14797
|
+
const dirs = [builtInDir(), userDir()];
|
|
14798
|
+
for (const dir2 of dirs) {
|
|
14799
|
+
if (!(0, import_node_fs14.existsSync)(dir2)) continue;
|
|
14800
|
+
let entries;
|
|
14801
|
+
try {
|
|
14802
|
+
entries = (0, import_node_fs14.readdirSync)(dir2);
|
|
14803
|
+
} catch {
|
|
14804
|
+
continue;
|
|
14805
|
+
}
|
|
14806
|
+
for (const entry of entries) {
|
|
14807
|
+
if (!entry.endsWith(".json")) continue;
|
|
14808
|
+
const fullPath = (0, import_node_path15.join)(dir2, entry);
|
|
14809
|
+
try {
|
|
14810
|
+
const st = (0, import_node_fs14.statSync)(fullPath);
|
|
14811
|
+
if (!st.isFile()) continue;
|
|
14812
|
+
const raw = (0, import_node_fs14.readFileSync)(fullPath, "utf-8");
|
|
14813
|
+
const parsed = JSON.parse(raw);
|
|
14814
|
+
const errors = validateSkill(parsed);
|
|
14815
|
+
if (errors.length > 0) {
|
|
14816
|
+
console.warn(`[skills] ${entry} invalid, skipping: ${errors.map((e) => `${e.path}: ${e.message}`).join("; ")}`);
|
|
14817
|
+
continue;
|
|
14818
|
+
}
|
|
14819
|
+
all.set(parsed.id, parsed);
|
|
14820
|
+
} catch (err) {
|
|
14821
|
+
console.warn(`[skills] could not load ${fullPath}: ${err.message}`);
|
|
14822
|
+
}
|
|
14823
|
+
}
|
|
14824
|
+
}
|
|
14825
|
+
return all;
|
|
14826
|
+
}
|
|
14827
|
+
function ensureLoaded() {
|
|
14828
|
+
const now = Date.now();
|
|
14829
|
+
if (cache.byId && now - cache.ts < CACHE_TTL_MS) return cache.byId;
|
|
14830
|
+
const fresh = loadAllSkillsFromDisk();
|
|
14831
|
+
cache.byId = fresh;
|
|
14832
|
+
cache.ts = now;
|
|
14833
|
+
return fresh;
|
|
14834
|
+
}
|
|
14835
|
+
function invalidateSkillCache() {
|
|
14836
|
+
cache.byId = null;
|
|
14837
|
+
cache.ts = 0;
|
|
14838
|
+
}
|
|
14839
|
+
function validateSkill(s) {
|
|
14840
|
+
const errs = [];
|
|
14841
|
+
if (!s || typeof s !== "object" || Array.isArray(s)) {
|
|
14842
|
+
return [{ path: "$", message: "skill must be a JSON object" }];
|
|
14843
|
+
}
|
|
14844
|
+
const sk = s;
|
|
14845
|
+
const requireString = (key, minLen = 1) => {
|
|
14846
|
+
const v = sk[key];
|
|
14847
|
+
if (typeof v !== "string" || v.length < minLen) {
|
|
14848
|
+
errs.push({ path: key, message: `must be a non-empty string` });
|
|
14849
|
+
}
|
|
14850
|
+
};
|
|
14851
|
+
const requireArray = (key, minLen = 1) => {
|
|
14852
|
+
const v = sk[key];
|
|
14853
|
+
if (!Array.isArray(v) || v.length < minLen) {
|
|
14854
|
+
errs.push({ path: key, message: `must be a non-empty array` });
|
|
14855
|
+
}
|
|
14856
|
+
};
|
|
14857
|
+
requireString("id");
|
|
14858
|
+
if (typeof sk.id === "string" && !/^[a-z0-9]+(-[a-z0-9]+)*$/.test(sk.id)) {
|
|
14859
|
+
errs.push({ path: "id", message: "must be lowercase-hyphenated slug (a-z, 0-9, -)" });
|
|
14860
|
+
}
|
|
14861
|
+
requireString("name");
|
|
14862
|
+
requireString("version");
|
|
14863
|
+
requireString("description");
|
|
14864
|
+
requireString("category");
|
|
14865
|
+
const validCategories = [
|
|
14866
|
+
"negotiation",
|
|
14867
|
+
"customer-service",
|
|
14868
|
+
"reservations",
|
|
14869
|
+
"medical-admin",
|
|
14870
|
+
"legal-admin",
|
|
14871
|
+
"finance-admin",
|
|
14872
|
+
"real-estate",
|
|
14873
|
+
"travel",
|
|
14874
|
+
"subscription",
|
|
14875
|
+
"home-services",
|
|
14876
|
+
"social",
|
|
14877
|
+
"civic",
|
|
14878
|
+
"employment",
|
|
14879
|
+
"debt-collection",
|
|
14880
|
+
"other"
|
|
14881
|
+
];
|
|
14882
|
+
if (typeof sk.category === "string" && !validCategories.includes(sk.category)) {
|
|
14883
|
+
errs.push({ path: "category", message: `unknown category "${sk.category}"; must be one of: ${validCategories.join(", ")}` });
|
|
14884
|
+
}
|
|
14885
|
+
if (!Array.isArray(sk.tags)) errs.push({ path: "tags", message: "must be an array of strings" });
|
|
14886
|
+
if (sk.disclaimer !== null && typeof sk.disclaimer !== "string") {
|
|
14887
|
+
errs.push({ path: "disclaimer", message: "must be a string or null" });
|
|
14888
|
+
}
|
|
14889
|
+
if (!sk.context || typeof sk.context !== "object") {
|
|
14890
|
+
errs.push({ path: "context", message: "must be an object" });
|
|
14891
|
+
} else {
|
|
14892
|
+
const ctx = sk.context;
|
|
14893
|
+
if (typeof ctx.when_to_use !== "string") errs.push({ path: "context.when_to_use", message: "must be a string" });
|
|
14894
|
+
if (!Array.isArray(ctx.preconditions)) errs.push({ path: "context.preconditions", message: "must be an array" });
|
|
14895
|
+
if (typeof ctx.estimated_call_duration_minutes !== "number") errs.push({ path: "context.estimated_call_duration_minutes", message: "must be a number" });
|
|
14896
|
+
}
|
|
14897
|
+
requireArray("principles", 2);
|
|
14898
|
+
if (!sk.phrases || typeof sk.phrases !== "object") errs.push({ path: "phrases", message: "must be an object of {key: phrase}" });
|
|
14899
|
+
if (!Array.isArray(sk.tactics) || sk.tactics.length === 0) {
|
|
14900
|
+
errs.push({ path: "tactics", message: "must be a non-empty array" });
|
|
14901
|
+
} else {
|
|
14902
|
+
sk.tactics.forEach((t, i) => {
|
|
14903
|
+
if (!t || typeof t !== "object") {
|
|
14904
|
+
errs.push({ path: `tactics[${i}]`, message: "must be an object" });
|
|
14905
|
+
return;
|
|
14906
|
+
}
|
|
14907
|
+
const tactic = t;
|
|
14908
|
+
if (typeof tactic.name !== "string") errs.push({ path: `tactics[${i}].name`, message: "must be a string" });
|
|
14909
|
+
if (typeof tactic.when !== "string") errs.push({ path: `tactics[${i}].when`, message: "must be a string" });
|
|
14910
|
+
if (typeof tactic.script !== "string" || tactic.script.length < 5) {
|
|
14911
|
+
errs.push({ path: `tactics[${i}].script`, message: "must be a non-empty string (>= 5 chars)" });
|
|
14912
|
+
}
|
|
14913
|
+
});
|
|
14914
|
+
}
|
|
14915
|
+
requireArray("boundaries", 1);
|
|
14916
|
+
if (!Array.isArray(sk.success_signals)) errs.push({ path: "success_signals", message: "must be an array" });
|
|
14917
|
+
if (!Array.isArray(sk.failure_signals)) errs.push({ path: "failure_signals", message: "must be an array" });
|
|
14918
|
+
if (!sk.exit_strategy || typeof sk.exit_strategy !== "object") {
|
|
14919
|
+
errs.push({ path: "exit_strategy", message: "must be an object" });
|
|
14920
|
+
} else {
|
|
14921
|
+
const xs = sk.exit_strategy;
|
|
14922
|
+
if (typeof xs.on_success !== "string") errs.push({ path: "exit_strategy.on_success", message: "must be a string" });
|
|
14923
|
+
if (typeof xs.on_failure !== "string") errs.push({ path: "exit_strategy.on_failure", message: "must be a string" });
|
|
14924
|
+
}
|
|
14925
|
+
if (!Array.isArray(sk.required_user_info)) errs.push({ path: "required_user_info", message: "must be an array" });
|
|
14926
|
+
if (typeof sk.contributed_by !== "string") errs.push({ path: "contributed_by", message: "must be a string" });
|
|
14927
|
+
return errs;
|
|
14928
|
+
}
|
|
14929
|
+
function summarize(s) {
|
|
14930
|
+
return {
|
|
14931
|
+
id: s.id,
|
|
14932
|
+
name: s.name,
|
|
14933
|
+
category: s.category,
|
|
14934
|
+
tags: s.tags,
|
|
14935
|
+
description: s.description,
|
|
14936
|
+
version: s.version,
|
|
14937
|
+
disclaimer_required: !!s.disclaimer,
|
|
14938
|
+
estimated_call_duration_minutes: s.context.estimated_call_duration_minutes
|
|
14939
|
+
};
|
|
14940
|
+
}
|
|
14941
|
+
function listSkills(opts = {}) {
|
|
14942
|
+
const all = Array.from(ensureLoaded().values());
|
|
14943
|
+
const filtered = all.filter((s) => {
|
|
14944
|
+
if (opts.category && s.category !== opts.category) return false;
|
|
14945
|
+
if (opts.tag && !s.tags.includes(opts.tag.toLowerCase())) return false;
|
|
14946
|
+
return true;
|
|
14947
|
+
});
|
|
14948
|
+
return filtered.sort((a, b) => a.name.localeCompare(b.name)).map(summarize);
|
|
14949
|
+
}
|
|
14950
|
+
function searchSkills(query, limit = 20) {
|
|
14951
|
+
const q = query.toLowerCase().trim();
|
|
14952
|
+
if (!q) return listSkills();
|
|
14953
|
+
const all = Array.from(ensureLoaded().values());
|
|
14954
|
+
const scored = [];
|
|
14955
|
+
for (const s of all) {
|
|
14956
|
+
let score = 0;
|
|
14957
|
+
if (s.id.toLowerCase().includes(q)) score += 10;
|
|
14958
|
+
if (s.name.toLowerCase().includes(q)) score += 8;
|
|
14959
|
+
if (s.tags.some((t) => t.toLowerCase().includes(q))) score += 5;
|
|
14960
|
+
if (s.category.toLowerCase().includes(q)) score += 4;
|
|
14961
|
+
if (s.description.toLowerCase().includes(q)) score += 3;
|
|
14962
|
+
if (s.principles.some((p) => p.toLowerCase().includes(q))) score += 2;
|
|
14963
|
+
if (Object.values(s.phrases).some((p) => p.toLowerCase().includes(q))) score += 2;
|
|
14964
|
+
if (s.tactics.some((t) => t.script.toLowerCase().includes(q) || t.name.toLowerCase().includes(q))) score += 2;
|
|
14965
|
+
if (score > 0) scored.push({ skill: s, score });
|
|
14966
|
+
}
|
|
14967
|
+
scored.sort((a, b) => b.score - a.score || a.skill.name.localeCompare(b.skill.name));
|
|
14968
|
+
return scored.slice(0, limit).map((x) => summarize(x.skill));
|
|
14969
|
+
}
|
|
14970
|
+
function loadSkill(id) {
|
|
14971
|
+
return ensureLoaded().get(id) ?? null;
|
|
14972
|
+
}
|
|
14973
|
+
function saveUserSkill(skill) {
|
|
14974
|
+
const errors = validateSkill(skill);
|
|
14975
|
+
if (errors.length > 0) {
|
|
14976
|
+
throw new Error(`skill validation failed: ${errors.map((e) => `${e.path}: ${e.message}`).join("; ")}`);
|
|
14977
|
+
}
|
|
14978
|
+
const dir2 = userDir();
|
|
14979
|
+
const path2 = (0, import_node_path15.join)(dir2, `${skill.id}.json`);
|
|
14980
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
14981
|
+
const out = {
|
|
14982
|
+
...skill,
|
|
14983
|
+
created_at: skill.created_at ?? now,
|
|
14984
|
+
updated_at: now
|
|
14985
|
+
};
|
|
14986
|
+
(0, import_node_fs14.writeFileSync)(path2, JSON.stringify(out, null, 2), "utf-8");
|
|
14987
|
+
invalidateSkillCache();
|
|
14988
|
+
return { path: path2 };
|
|
14989
|
+
}
|
|
14990
|
+
function userSkillsDir() {
|
|
14991
|
+
return userDir();
|
|
14992
|
+
}
|
|
14993
|
+
|
|
14994
|
+
// src/skills/index.ts
|
|
14995
|
+
function renderSkillAsPrompt(skill) {
|
|
14996
|
+
const lines = [];
|
|
14997
|
+
lines.push(`=== SKILL LOADED: ${skill.name} (v${skill.version}) ===`);
|
|
14998
|
+
lines.push(`Category: ${skill.category} Tags: ${skill.tags.join(", ")}`);
|
|
14999
|
+
lines.push("");
|
|
15000
|
+
lines.push(skill.description);
|
|
15001
|
+
lines.push("");
|
|
15002
|
+
if (skill.disclaimer) {
|
|
15003
|
+
lines.push("REQUIRED DISCLAIMER (recite at start of the substantive turn):");
|
|
15004
|
+
lines.push(` "${skill.disclaimer}"`);
|
|
15005
|
+
lines.push("");
|
|
15006
|
+
}
|
|
15007
|
+
lines.push("WHEN TO USE THIS:");
|
|
15008
|
+
lines.push(` ${skill.context.when_to_use}`);
|
|
15009
|
+
if (skill.context.preconditions.length > 0) {
|
|
15010
|
+
lines.push("Preconditions:");
|
|
15011
|
+
for (const p of skill.context.preconditions) lines.push(` - ${p}`);
|
|
15012
|
+
}
|
|
15013
|
+
lines.push("");
|
|
15014
|
+
lines.push("PRINCIPLES:");
|
|
15015
|
+
for (const p of skill.principles) lines.push(` - ${p}`);
|
|
15016
|
+
lines.push("");
|
|
15017
|
+
if (Object.keys(skill.phrases).length > 0) {
|
|
15018
|
+
lines.push("PHRASES (paraphrase to match your voice; keep the structural move):");
|
|
15019
|
+
for (const [k, v] of Object.entries(skill.phrases)) lines.push(` [${k}] "${v}"`);
|
|
15020
|
+
lines.push("");
|
|
15021
|
+
}
|
|
15022
|
+
if (skill.tactics.length > 0) {
|
|
15023
|
+
lines.push("TACTICS (try in order; fall back to next on failure):");
|
|
15024
|
+
skill.tactics.forEach((t, i) => {
|
|
15025
|
+
lines.push(` ${i + 1}. ${t.name}`);
|
|
15026
|
+
lines.push(` When: ${t.when}`);
|
|
15027
|
+
lines.push(` Script: "${t.script}"`);
|
|
15028
|
+
});
|
|
15029
|
+
lines.push("");
|
|
15030
|
+
}
|
|
15031
|
+
if (skill.boundaries.length > 0) {
|
|
15032
|
+
lines.push("HARD BOUNDARIES \u2014 do not cross:");
|
|
15033
|
+
for (const b of skill.boundaries) lines.push(` - ${b}`);
|
|
15034
|
+
lines.push("");
|
|
15035
|
+
}
|
|
15036
|
+
lines.push("SUCCESS SIGNALS:");
|
|
15037
|
+
for (const s of skill.success_signals) lines.push(` - ${s}`);
|
|
15038
|
+
lines.push("");
|
|
15039
|
+
lines.push("FAILURE SIGNALS \u2014 when these appear, escalate or exit:");
|
|
15040
|
+
for (const s of skill.failure_signals) lines.push(` - ${s}`);
|
|
15041
|
+
lines.push("");
|
|
15042
|
+
lines.push("EXIT:");
|
|
15043
|
+
lines.push(` On success: ${skill.exit_strategy.on_success}`);
|
|
15044
|
+
lines.push(` On failure: ${skill.exit_strategy.on_failure}`);
|
|
15045
|
+
if (skill.exit_strategy.follow_ups && skill.exit_strategy.follow_ups.length > 0) {
|
|
15046
|
+
lines.push(" Follow-ups (after the call):");
|
|
15047
|
+
for (const f of skill.exit_strategy.follow_ups) lines.push(` - ${f}`);
|
|
15048
|
+
}
|
|
15049
|
+
lines.push("");
|
|
15050
|
+
lines.push("=== END SKILL ===");
|
|
15051
|
+
return lines.join("\n");
|
|
15052
|
+
}
|
|
14766
15053
|
// Annotate the CommonJS export names for ESM import in node:
|
|
14767
15054
|
0 && (module.exports = {
|
|
14768
15055
|
AGENT_ROLES,
|
|
@@ -14908,6 +15195,7 @@ var AgentMemoryManager = class {
|
|
|
14908
15195
|
getTelegramWebhookInfo,
|
|
14909
15196
|
hostSessionStoragePath,
|
|
14910
15197
|
inferPhoneRegion,
|
|
15198
|
+
invalidateSkillCache,
|
|
14911
15199
|
isInternalEmail,
|
|
14912
15200
|
isLoopbackMailHost,
|
|
14913
15201
|
isOperatorReplySender,
|
|
@@ -14916,7 +15204,9 @@ var AgentMemoryManager = class {
|
|
|
14916
15204
|
isTelegramChatAllowed,
|
|
14917
15205
|
isTelegramStopCommand,
|
|
14918
15206
|
isValidPhoneNumber,
|
|
15207
|
+
listSkills,
|
|
14919
15208
|
loadHostSession,
|
|
15209
|
+
loadSkill,
|
|
14920
15210
|
mapProviderSmsStatus,
|
|
14921
15211
|
nextTelegramOffset,
|
|
14922
15212
|
normalizeAddress,
|
|
@@ -14941,6 +15231,7 @@ var AgentMemoryManager = class {
|
|
|
14941
15231
|
redactSecret,
|
|
14942
15232
|
redactSmsConfig,
|
|
14943
15233
|
redactTelegramConfig,
|
|
15234
|
+
renderSkillAsPrompt,
|
|
14944
15235
|
requireBinary,
|
|
14945
15236
|
requireWhisperModel,
|
|
14946
15237
|
resolveConfig,
|
|
@@ -14949,8 +15240,10 @@ var AgentMemoryManager = class {
|
|
|
14949
15240
|
sanitizeEmail,
|
|
14950
15241
|
saveConfig,
|
|
14951
15242
|
saveHostSession,
|
|
15243
|
+
saveUserSkill,
|
|
14952
15244
|
scanOutboundEmail,
|
|
14953
15245
|
scoreEmail,
|
|
15246
|
+
searchSkills,
|
|
14954
15247
|
sendTelegramMessage,
|
|
14955
15248
|
setOperatorEmail,
|
|
14956
15249
|
setTelegramWebhook,
|
|
@@ -14963,10 +15256,12 @@ var AgentMemoryManager = class {
|
|
|
14963
15256
|
threadIdFor,
|
|
14964
15257
|
tokenize,
|
|
14965
15258
|
tryJoin,
|
|
15259
|
+
userSkillsDir,
|
|
14966
15260
|
validateApiUrl,
|
|
14967
15261
|
validatePhoneMissionPolicy,
|
|
14968
15262
|
validatePhoneMissionStart,
|
|
14969
15263
|
validatePhoneTransportProfile,
|
|
15264
|
+
validateSkill,
|
|
14970
15265
|
validateTwilioSignature,
|
|
14971
15266
|
webSearch
|
|
14972
15267
|
});
|