kushi-agents 6.4.0 → 6.5.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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kushi-agents",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.5.0",
|
|
4
4
|
"description": "Install Kushi — multi-source project evidence agent with Comprehensive Structured Capture (CSC) into weekly-only files across Email, Teams, OneNote, Loop, SharePoint, Meetings, CRM, ADO. Meetings retain a sibling verbatim/ audit folder. WorkIQ-only for M365 sources (Graph / m365_* FORBIDDEN as fallbacks; user-paste is first-class). Host-agnostic.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -234,8 +234,8 @@ async function interactiveSetup({ workspace, dryRun }) {
|
|
|
234
234
|
function emit(obj) { process.stdout.write(JSON.stringify(obj) + '\n'); }
|
|
235
235
|
|
|
236
236
|
const INTEGRATIONS_TEMPLATE = {
|
|
237
|
-
crm: { instance: 'https://iscrm.crm.dynamics.com', table: 'incidents', request_id:
|
|
238
|
-
ado: { organization: 'IndustrySolutions', project: 'IS Engagements', apiVersion: '7.1', engagement_id:
|
|
237
|
+
crm: { instance: 'https://iscrm.crm.dynamics.com', table: 'incidents', request_id: '<__FILL_ME_IN__>', record_id: '<__FILL_ME_IN__>' },
|
|
238
|
+
ado: { organization: 'IndustrySolutions', project: 'IS Engagements', apiVersion: '7.1', engagement_id: '<__FILL_ME_IN__>' },
|
|
239
239
|
sharepoint: { allowed_tenants: [] },
|
|
240
240
|
};
|
|
241
241
|
|
|
@@ -252,17 +252,26 @@ function applyRows(source, rows, currentBounds, currentInteg) {
|
|
|
252
252
|
}
|
|
253
253
|
if (source === 'meetings') {
|
|
254
254
|
const existing = currentBounds.meetings?.joinUrls || [];
|
|
255
|
+
// v6.5.0: meeting boundaries MUST be real http(s) join URLs — pull-meetings
|
|
256
|
+
// can't resolve a subject string into a meeting at the WorkIQ layer (unlike
|
|
257
|
+
// teams chat topics). Reject anything that isn't a URL; track rejected
|
|
258
|
+
// subjects in `accepted` log via reason field for discover-report visibility.
|
|
259
|
+
const rejectedSubjects = [];
|
|
255
260
|
const incoming = rows.map(r => {
|
|
256
261
|
const url = r.join_url;
|
|
257
|
-
if (url && !isPlaceholder(url) && isValidValueFor('meetings', 'join_url', url) && url
|
|
262
|
+
if (url && !isPlaceholder(url) && isValidValueFor('meetings', 'join_url', url) && /^https?:\/\//.test(url)) return url;
|
|
258
263
|
const subj = r.subject;
|
|
259
|
-
if (subj && !isPlaceholder(subj))
|
|
264
|
+
if (subj && !isPlaceholder(subj)) rejectedSubjects.push(subj);
|
|
260
265
|
return null;
|
|
261
266
|
}).filter(Boolean);
|
|
262
267
|
const merged = dedup([...existing, ...incoming]);
|
|
263
268
|
const added = merged.filter(v => !existing.includes(v));
|
|
264
269
|
if (added.length) accepted.push(...added);
|
|
265
|
-
return {
|
|
270
|
+
return {
|
|
271
|
+
boundariesPatch: added.length ? { meetings: { joinUrls: merged } } : null,
|
|
272
|
+
accepted,
|
|
273
|
+
rejected: rejectedSubjects.length ? rejectedSubjects.map(s => ({ subject: s, reason: 'no-join-url' })) : undefined,
|
|
274
|
+
};
|
|
266
275
|
}
|
|
267
276
|
if (source === 'onenote') {
|
|
268
277
|
const existing = currentBounds.onenote?.section_file_ids || [];
|
|
@@ -303,7 +312,7 @@ function applyRows(source, rows, currentBounds, currentInteg) {
|
|
|
303
312
|
isValidValueFor('crm', 'request_id', r.request_id) ||
|
|
304
313
|
isValidValueFor('crm', 'incident_number', r.incident_number)
|
|
305
314
|
);
|
|
306
|
-
if (!top) return { integrationsPatch: null, accepted: [] };
|
|
315
|
+
if (!top) return { integrationsPatch: null, accepted: [], unresolved: 'crm.request_id' };
|
|
307
316
|
const id = isValidValueFor('crm', 'request_id', top.request_id) ? top.request_id : top.incident_number;
|
|
308
317
|
const patch = { crm: { ...cur, request_id: id } };
|
|
309
318
|
accepted.push(id);
|
|
@@ -318,7 +327,7 @@ function applyRows(source, rows, currentBounds, currentInteg) {
|
|
|
318
327
|
isValidValueFor('ado', 'engagement_id', r.engagement_id) ||
|
|
319
328
|
isValidValueFor('ado', 'work_item_id', r.work_item_id)
|
|
320
329
|
);
|
|
321
|
-
if (!top) return { integrationsPatch: null, accepted: [] };
|
|
330
|
+
if (!top) return { integrationsPatch: null, accepted: [], unresolved: 'ado.engagement_id' };
|
|
322
331
|
const id = isValidValueFor('ado', 'engagement_id', top.engagement_id) ? top.engagement_id : top.work_item_id;
|
|
323
332
|
const patch = { ado: { ...cur, engagement_id: id } };
|
|
324
333
|
accepted.push(id);
|
|
@@ -448,7 +457,7 @@ async function main() {
|
|
|
448
457
|
: `${skipReason} after ${elapsed}ms: ${(e.message || '').split('\n')[0].slice(0, 200)}`;
|
|
449
458
|
log(` ${source}: ✗ ${detail}`);
|
|
450
459
|
}
|
|
451
|
-
const { boundariesPatch, integrationsPatch, accepted } = applyRows(source, rows, bounds, integ);
|
|
460
|
+
const { boundariesPatch, integrationsPatch, accepted, rejected, unresolved } = applyRows(source, rows, bounds, integ);
|
|
452
461
|
if (boundariesPatch) {
|
|
453
462
|
Object.assign(bounds, mergeShallow(bounds, boundariesPatch));
|
|
454
463
|
boundsDirty = true;
|
|
@@ -457,7 +466,7 @@ async function main() {
|
|
|
457
466
|
Object.assign(integ, mergeShallow(integ, integrationsPatch));
|
|
458
467
|
integDirty = true;
|
|
459
468
|
}
|
|
460
|
-
sourceResults.push({ source, asked, found: rows.length, accepted, skipped_reason: skipReason });
|
|
469
|
+
sourceResults.push({ source, asked, found: rows.length, accepted, rejected, unresolved, skipped_reason: skipReason });
|
|
461
470
|
}
|
|
462
471
|
|
|
463
472
|
log(`done: ${sourceResults.filter(r => r.found > 0).length}/${total} sources returned data`);
|
|
@@ -73,13 +73,14 @@ function emit(obj) { process.stdout.write(JSON.stringify(obj) + '\n'); }
|
|
|
73
73
|
*/
|
|
74
74
|
export function buildTargets(merged) {
|
|
75
75
|
const targets = [];
|
|
76
|
+
const isPlaceholder = (v) => v == null || /^<.*>$/.test(String(v).trim()) || /^(unknown|n\/a|none|null|tbd|todo)$/i.test(String(v).trim());
|
|
76
77
|
// crm: from integrations
|
|
77
78
|
const crm = merged.crm || {};
|
|
78
79
|
const crmEntity = crm.request_id || crm.record_id;
|
|
79
|
-
if (crmEntity) targets.push({ source: 'crm', entity: String(crmEntity) });
|
|
80
|
+
if (crmEntity && !isPlaceholder(crmEntity)) targets.push({ source: 'crm', entity: String(crmEntity) });
|
|
80
81
|
// ado
|
|
81
82
|
const ado = merged.ado || {};
|
|
82
|
-
if (ado.engagement_id) targets.push({ source: 'ado', entity: String(ado.engagement_id) });
|
|
83
|
+
if (ado.engagement_id && !isPlaceholder(ado.engagement_id)) targets.push({ source: 'ado', entity: String(ado.engagement_id) });
|
|
83
84
|
// email: per-user mailbox folders
|
|
84
85
|
const email = merged.email || {};
|
|
85
86
|
for (const f of (email.folders || [])) {
|