@datarails-ai/dr-cli 0.0.1-locked → 1.6.71
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 +608 -0
- package/dist/chunk-DWMCBGQH.js +242 -0
- package/dist/cli.js +64468 -0
- package/dist/kb-6UWI7Q32.js +21 -0
- package/dist/scopes-map.json +4412 -0
- package/dist/skills/connector-sandbox/SKILL.md +95 -0
- package/dist/skills/datarails-connect-workato/SKILL.md +140 -0
- package/dist/skills/datarails-connectors-onboard-connector/SKILL.md +813 -0
- package/dist/skills/dr-cli/SKILL.md +659 -0
- package/dist/skills/dr-cli/reference/admin.md +796 -0
- package/dist/skills/dr-cli/reference/budget-builder.md +151 -0
- package/dist/skills/dr-cli/reference/calc-vals.md +73 -0
- package/dist/skills/dr-cli/reference/calcmodels.md +76 -0
- package/dist/skills/dr-cli/reference/cash.md +61 -0
- package/dist/skills/dr-cli/reference/dashboards-widgets.md +85 -0
- package/dist/skills/dr-cli/reference/datamappers.md +150 -0
- package/dist/skills/dr-cli/reference/desk.md +472 -0
- package/dist/skills/dr-cli/reference/filebox-documents.md +373 -0
- package/dist/skills/dr-cli/reference/forecast.md +51 -0
- package/dist/skills/dr-cli/reference/integrations.md +57 -0
- package/dist/skills/dr-cli/reference/lookups.md +168 -0
- package/dist/skills/dr-cli/reference/metrics.md +512 -0
- package/dist/skills/dr-cli/reference/multi-product.md +180 -0
- package/dist/skills/dr-cli/reference/reconciliation-mec.md +76 -0
- package/dist/skills/dr-cli/reference/rh-config.md +84 -0
- package/dist/skills/dr-cli/reference/safety.md +143 -0
- package/dist/skills/dr-cli/reference/spend-control.md +206 -0
- package/dist/skills/dr-cli/reference/templates.md +163 -0
- package/dist/skills/dr-cli/reference/workflows.md +137 -0
- package/dist/skills/dr-error-enrichment/SKILL.md +80 -0
- package/dist/skills/dr-error-enrichment/reference/core.md +257 -0
- package/dist/skills/dr-error-enrichment/reference/groundcover.md +84 -0
- package/dist/skills/dr-error-enrichment/reference/jira-bugs.md +219 -0
- package/dist/skills/dr-error-enrichment/reference/safety-backup.md +122 -0
- package/dist/skills/dr-error-enrichment-author/SKILL.md +219 -0
- package/dist/skills/dr-error-enrichment-improve/SKILL.md +218 -0
- package/dist/skills/dr-error-enrichment-maintain/SKILL.md +237 -0
- package/dist/skills/dr-error-enrichment-reconcile/SKILL.md +167 -0
- package/dist/skills/dr-filebox-api-setup/SKILL.md +170 -0
- package/dist/skills/dr-switch-user/SKILL.md +395 -0
- package/dist/skills/dr-validate/SKILL.md +392 -0
- package/dist/skills/dr-validate/report-template.html +950 -0
- package/dist/skills/fx-conversion-matrix/SKILL.md +763 -0
- package/dist/skills/fx-conversion-matrix/scripts/_args.mjs +52 -0
- package/dist/skills/fx-conversion-matrix/scripts/_xlsx.mjs +241 -0
- package/dist/skills/fx-conversion-matrix/scripts/build-matrix.mjs +366 -0
- package/dist/skills/fx-conversion-matrix/scripts/gen-mappers.mjs +171 -0
- package/dist/skills/fx-conversion-matrix/scripts/rates-to-xlsx.mjs +172 -0
- package/dist/skills/fx-onboard/SKILL.md +325 -0
- package/dist/skills/mec-table-validation/SKILL.md +383 -0
- package/dist/skills/plugins.json +24 -0
- package/dist/skills/validate-workato-migration/SKILL.md +167 -0
- package/dist/skills/validate-workato-migration/reference/gotchas.md +16 -0
- package/dist/skills/validate-workato-migration/reference/staging-orgs.md +26 -0
- package/dist/skills/validate-workato-migration/scripts/compare_files.py +255 -0
- package/dist/zendeskKb-JPSHVOPH.js +243 -0
- package/package.json +56 -9
- package/scripts/postinstall.mjs +91 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/api/kb.ts
|
|
4
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
5
|
+
import { join, resolve } from "path";
|
|
6
|
+
|
|
7
|
+
// src/api/_kbHtml.ts
|
|
8
|
+
import { parse as parseHtml } from "node-html-parser";
|
|
9
|
+
import TurndownService from "turndown";
|
|
10
|
+
var turndown = new TurndownService({
|
|
11
|
+
headingStyle: "atx",
|
|
12
|
+
codeBlockStyle: "fenced"
|
|
13
|
+
});
|
|
14
|
+
function preserveIframes(html) {
|
|
15
|
+
const root = parseHtml(html);
|
|
16
|
+
for (const iframe of root.querySelectorAll("iframe")) {
|
|
17
|
+
const src = iframe.getAttribute("src");
|
|
18
|
+
if (src === void 0 || src === "") {
|
|
19
|
+
iframe.remove();
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
iframe.replaceWith(parseHtml(`<a href="${src}">Embedded video: ${src}</a>`));
|
|
23
|
+
}
|
|
24
|
+
return root.toString();
|
|
25
|
+
}
|
|
26
|
+
function toMarkdown(bodyHtml) {
|
|
27
|
+
if (bodyHtml === null || bodyHtml === void 0 || bodyHtml === "") {
|
|
28
|
+
return "";
|
|
29
|
+
}
|
|
30
|
+
return turndown.turndown(preserveIframes(bodyHtml)).trim();
|
|
31
|
+
}
|
|
32
|
+
function extractImageUrls(bodyHtml) {
|
|
33
|
+
if (bodyHtml === null || bodyHtml === void 0 || bodyHtml === "") {
|
|
34
|
+
return [];
|
|
35
|
+
}
|
|
36
|
+
const root = parseHtml(bodyHtml);
|
|
37
|
+
const out = [];
|
|
38
|
+
const seen = /* @__PURE__ */ new Set();
|
|
39
|
+
for (const img of root.querySelectorAll("img")) {
|
|
40
|
+
const src = img.getAttribute("src");
|
|
41
|
+
if (src !== void 0 && src !== "" && !seen.has(src)) {
|
|
42
|
+
seen.add(src);
|
|
43
|
+
out.push(src);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/api/kb.ts
|
|
50
|
+
var SUBDOMAIN = process.env.ZENDESK_SUBDOMAIN ?? "datarails";
|
|
51
|
+
var BASE_URL = `https://${SUBDOMAIN}.zendesk.com/api/v2/help_center`;
|
|
52
|
+
function authHeader() {
|
|
53
|
+
const email = process.env.ZENDESK_EMAIL;
|
|
54
|
+
const token = process.env.ZENDESK_API_TOKEN;
|
|
55
|
+
if (email !== void 0 && token !== void 0) {
|
|
56
|
+
const creds = Buffer.from(`${email}/token:${token}`).toString("base64");
|
|
57
|
+
return { Authorization: `Basic ${creds}` };
|
|
58
|
+
}
|
|
59
|
+
return {};
|
|
60
|
+
}
|
|
61
|
+
async function zget(url) {
|
|
62
|
+
return fetch(url, { headers: authHeader() });
|
|
63
|
+
}
|
|
64
|
+
function clamp(n, lo, hi) {
|
|
65
|
+
return Math.max(lo, Math.min(n, hi));
|
|
66
|
+
}
|
|
67
|
+
function toArticle(a) {
|
|
68
|
+
return {
|
|
69
|
+
id: a.id ?? 0,
|
|
70
|
+
title: a.title ?? "",
|
|
71
|
+
url: a.html_url ?? "",
|
|
72
|
+
section_id: a.section_id ?? 0,
|
|
73
|
+
updated_at: a.updated_at ?? "",
|
|
74
|
+
body: toMarkdown(a.body)
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function toArticleMeta(a) {
|
|
78
|
+
return {
|
|
79
|
+
id: a.id ?? 0,
|
|
80
|
+
title: a.title ?? "",
|
|
81
|
+
url: a.html_url ?? "",
|
|
82
|
+
section_id: a.section_id ?? 0,
|
|
83
|
+
updated_at: a.updated_at ?? ""
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
async function search(args) {
|
|
87
|
+
const locale = args.locale ?? "en-us";
|
|
88
|
+
const limit = clamp(args.limit ?? 5, 1, 100);
|
|
89
|
+
const url = `${BASE_URL}/articles/search.json?query=${encodeURIComponent(args.query)}&locale=${encodeURIComponent(locale)}&per_page=${limit}`;
|
|
90
|
+
const r = await zget(url);
|
|
91
|
+
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
|
92
|
+
const data = await r.json();
|
|
93
|
+
return (data.results ?? []).slice(0, limit).map(toArticle);
|
|
94
|
+
}
|
|
95
|
+
async function fetchArticleRaw(articleId, locale) {
|
|
96
|
+
const r = await zget(`${BASE_URL}/${locale}/articles/${articleId}.json`);
|
|
97
|
+
if (r.status === 404) return null;
|
|
98
|
+
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
|
99
|
+
const data = await r.json();
|
|
100
|
+
return data.article ?? null;
|
|
101
|
+
}
|
|
102
|
+
async function getArticle(args) {
|
|
103
|
+
const raw = await fetchArticleRaw(args.article_id, args.locale ?? "en-us");
|
|
104
|
+
return raw !== null ? toArticle(raw) : null;
|
|
105
|
+
}
|
|
106
|
+
async function listCategories(args) {
|
|
107
|
+
const locale = args.locale ?? "en-us";
|
|
108
|
+
const r = await zget(`${BASE_URL}/${locale}/categories.json`);
|
|
109
|
+
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
|
110
|
+
const data = await r.json();
|
|
111
|
+
return (data.categories ?? []).map((c) => ({
|
|
112
|
+
id: c.id ?? 0,
|
|
113
|
+
name: c.name ?? "",
|
|
114
|
+
description: c.description ?? "",
|
|
115
|
+
url: c.html_url ?? ""
|
|
116
|
+
}));
|
|
117
|
+
}
|
|
118
|
+
async function listSections(args) {
|
|
119
|
+
const locale = args.locale ?? "en-us";
|
|
120
|
+
const limit = clamp(args.limit ?? 50, 1, 100);
|
|
121
|
+
const url = args.category_id !== void 0 ? `${BASE_URL}/${locale}/categories/${args.category_id}/sections.json?per_page=${limit}` : `${BASE_URL}/${locale}/sections.json?per_page=${limit}`;
|
|
122
|
+
const r = await zget(url);
|
|
123
|
+
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
|
124
|
+
const data = await r.json();
|
|
125
|
+
return (data.sections ?? []).slice(0, limit).map((s) => ({
|
|
126
|
+
id: s.id ?? 0,
|
|
127
|
+
name: s.name ?? "",
|
|
128
|
+
description: s.description ?? "",
|
|
129
|
+
category_id: s.category_id ?? 0,
|
|
130
|
+
url: s.html_url ?? ""
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
async function listArticlesInSection(args) {
|
|
134
|
+
const locale = args.locale ?? "en-us";
|
|
135
|
+
const limit = clamp(args.limit ?? 25, 1, 100);
|
|
136
|
+
const include = args.include_bodies ?? false;
|
|
137
|
+
const r = await zget(
|
|
138
|
+
`${BASE_URL}/${locale}/sections/${args.section_id}/articles.json?per_page=${limit}`
|
|
139
|
+
);
|
|
140
|
+
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
|
141
|
+
const data = await r.json();
|
|
142
|
+
return (data.articles ?? []).slice(0, limit).map((a) => include ? toArticle(a) : toArticleMeta(a));
|
|
143
|
+
}
|
|
144
|
+
async function listRecentArticles(args) {
|
|
145
|
+
const days = args.days ?? 30;
|
|
146
|
+
const locale = args.locale ?? "en-us";
|
|
147
|
+
const limit = clamp(args.limit ?? 25, 1, 100);
|
|
148
|
+
const cutoff = Date.now() - days * 864e5;
|
|
149
|
+
const r = await zget(
|
|
150
|
+
`${BASE_URL}/${locale}/articles.json?sort_by=updated_at&sort_order=desc&per_page=${limit}`
|
|
151
|
+
);
|
|
152
|
+
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
|
153
|
+
const data = await r.json();
|
|
154
|
+
const out = [];
|
|
155
|
+
for (const a of data.articles ?? []) {
|
|
156
|
+
const t = a.updated_at !== void 0 ? Date.parse(a.updated_at) : NaN;
|
|
157
|
+
if (Number.isNaN(t)) continue;
|
|
158
|
+
if (t < cutoff) break;
|
|
159
|
+
out.push(toArticleMeta(a));
|
|
160
|
+
if (out.length >= limit) break;
|
|
161
|
+
}
|
|
162
|
+
return out;
|
|
163
|
+
}
|
|
164
|
+
async function getArticleAttachments(args) {
|
|
165
|
+
const locale = args.locale ?? "en-us";
|
|
166
|
+
const r = await zget(`${BASE_URL}/${locale}/articles/${args.article_id}/attachments.json`);
|
|
167
|
+
if (r.status === 404) return [];
|
|
168
|
+
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
|
169
|
+
const data = await r.json();
|
|
170
|
+
return (data.article_attachments ?? []).map((a) => ({
|
|
171
|
+
id: a.id ?? 0,
|
|
172
|
+
file_name: a.file_name ?? "",
|
|
173
|
+
content_type: a.content_type ?? "",
|
|
174
|
+
content_url: a.content_url ?? "",
|
|
175
|
+
size: a.size ?? 0,
|
|
176
|
+
inline: a.inline ?? false
|
|
177
|
+
}));
|
|
178
|
+
}
|
|
179
|
+
var MAX_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
180
|
+
var CONTENT_TYPE_TO_EXT = {
|
|
181
|
+
"image/png": "png",
|
|
182
|
+
"image/jpeg": "jpg",
|
|
183
|
+
"image/jpg": "jpg",
|
|
184
|
+
"image/gif": "gif",
|
|
185
|
+
"image/webp": "webp"
|
|
186
|
+
};
|
|
187
|
+
async function articleImages(args) {
|
|
188
|
+
const locale = args.locale ?? "en-us";
|
|
189
|
+
const limit = clamp(args.limit ?? 5, 1, 10);
|
|
190
|
+
const raw = await fetchArticleRaw(args.article_id, locale);
|
|
191
|
+
if (raw === null) return [];
|
|
192
|
+
const urls = extractImageUrls(raw.body).slice(0, limit);
|
|
193
|
+
if (urls.length === 0) return [];
|
|
194
|
+
const absOut = resolve(args.out_dir);
|
|
195
|
+
await mkdir(absOut, { recursive: true });
|
|
196
|
+
const results = [];
|
|
197
|
+
let idx = 0;
|
|
198
|
+
for (const url of urls) {
|
|
199
|
+
idx++;
|
|
200
|
+
try {
|
|
201
|
+
const r = await fetch(url, { redirect: "follow" });
|
|
202
|
+
if (!r.ok) {
|
|
203
|
+
results.push({ url, skippedReason: `HTTP ${r.status}` });
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
const ct = (r.headers.get("content-type") ?? "").split(";")[0]?.trim().toLowerCase() ?? "";
|
|
207
|
+
const ext = CONTENT_TYPE_TO_EXT[ct];
|
|
208
|
+
if (ext === void 0) {
|
|
209
|
+
results.push({ url, skippedReason: `unsupported type '${ct}'` });
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
const buf = Buffer.from(await r.arrayBuffer());
|
|
213
|
+
if (buf.length > MAX_IMAGE_BYTES) {
|
|
214
|
+
results.push({
|
|
215
|
+
url,
|
|
216
|
+
skippedReason: `${buf.length} bytes > 5 MB cap`
|
|
217
|
+
});
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
const filename = `${args.article_id}-${idx}.${ext}`;
|
|
221
|
+
const filePath = join(absOut, filename);
|
|
222
|
+
await writeFile(filePath, buf);
|
|
223
|
+
results.push({ url, path: filePath });
|
|
224
|
+
} catch (err) {
|
|
225
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
226
|
+
results.push({ url, skippedReason: msg });
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return results;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export {
|
|
233
|
+
extractImageUrls,
|
|
234
|
+
search,
|
|
235
|
+
getArticle,
|
|
236
|
+
listCategories,
|
|
237
|
+
listSections,
|
|
238
|
+
listArticlesInSection,
|
|
239
|
+
listRecentArticles,
|
|
240
|
+
getArticleAttachments,
|
|
241
|
+
articleImages
|
|
242
|
+
};
|