@codemieai/code 0.3.2 → 0.4.1
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 +2 -0
- package/dist/agents/core/session/BaseSessionAdapter.d.ts +5 -2
- package/dist/agents/core/session/BaseSessionAdapter.d.ts.map +1 -1
- package/dist/agents/core/types.d.ts +11 -0
- package/dist/agents/core/types.d.ts.map +1 -1
- package/dist/agents/plugins/claude/claude.plugin.js +3 -3
- package/dist/agents/plugins/claude/claude.session.d.ts +13 -0
- package/dist/agents/plugins/claude/claude.session.d.ts.map +1 -1
- package/dist/agents/plugins/claude/claude.session.js +122 -42
- package/dist/agents/plugins/claude/claude.session.js.map +1 -1
- package/dist/agents/plugins/claude/plugin/.claude-plugin/plugin.json +1 -1
- package/dist/agents/plugins/claude/plugin/skills/codemie-analytics/scripts/analytics-cli.js +12 -8
- package/dist/agents/plugins/claude/plugin/skills/msgraph/SKILL.md +95 -8
- package/dist/agents/plugins/claude/plugin/skills/msgraph/scripts/msgraph.js +333 -2
- package/dist/agents/plugins/claude/plugin/statusline.mjs +11 -3
- package/dist/agents/plugins/claude/session/claude-file-operation.d.ts +38 -0
- package/dist/agents/plugins/claude/session/claude-file-operation.d.ts.map +1 -0
- package/dist/agents/plugins/claude/session/claude-file-operation.js +67 -0
- package/dist/agents/plugins/claude/session/claude-file-operation.js.map +1 -0
- package/dist/agents/plugins/claude/session/processors/claude.metrics-processor.d.ts +0 -4
- package/dist/agents/plugins/claude/session/processors/claude.metrics-processor.d.ts.map +1 -1
- package/dist/agents/plugins/claude/session/processors/claude.metrics-processor.js +7 -56
- package/dist/agents/plugins/claude/session/processors/claude.metrics-processor.js.map +1 -1
- package/dist/bin/proxy-daemon.js +54 -5
- package/dist/bin/proxy-daemon.js.map +1 -1
- package/dist/cli/commands/analytics/aggregator.d.ts +1 -1
- package/dist/cli/commands/analytics/aggregator.d.ts.map +1 -1
- package/dist/cli/commands/analytics/aggregator.js +84 -23
- package/dist/cli/commands/analytics/aggregator.js.map +1 -1
- package/dist/cli/commands/analytics/cost/cost-calculator.d.ts +10 -0
- package/dist/cli/commands/analytics/cost/cost-calculator.d.ts.map +1 -0
- package/dist/cli/commands/analytics/cost/cost-calculator.js +24 -0
- package/dist/cli/commands/analytics/cost/cost-calculator.js.map +1 -0
- package/dist/cli/commands/analytics/cost/cost-enricher.d.ts +24 -0
- package/dist/cli/commands/analytics/cost/cost-enricher.d.ts.map +1 -0
- package/dist/cli/commands/analytics/cost/cost-enricher.js +152 -0
- package/dist/cli/commands/analytics/cost/cost-enricher.js.map +1 -0
- package/dist/cli/commands/analytics/cost/pricing.d.ts +23 -0
- package/dist/cli/commands/analytics/cost/pricing.d.ts.map +1 -0
- package/dist/cli/commands/analytics/cost/pricing.js +82 -0
- package/dist/cli/commands/analytics/cost/pricing.js.map +1 -0
- package/dist/cli/commands/analytics/cost/pricing.json +975 -0
- package/dist/cli/commands/analytics/cost/types.d.ts +51 -0
- package/dist/cli/commands/analytics/cost/types.d.ts.map +1 -0
- package/dist/cli/commands/analytics/cost/types.js +8 -0
- package/dist/cli/commands/analytics/cost/types.js.map +1 -0
- package/dist/cli/commands/analytics/cost/usage-readers.d.ts +40 -0
- package/dist/cli/commands/analytics/cost/usage-readers.d.ts.map +1 -0
- package/dist/cli/commands/analytics/cost/usage-readers.js +165 -0
- package/dist/cli/commands/analytics/cost/usage-readers.js.map +1 -0
- package/dist/cli/commands/analytics/data-loader.d.ts +11 -0
- package/dist/cli/commands/analytics/data-loader.d.ts.map +1 -1
- package/dist/cli/commands/analytics/data-loader.js +7 -0
- package/dist/cli/commands/analytics/data-loader.js.map +1 -1
- package/dist/cli/commands/analytics/exporter.d.ts.map +1 -1
- package/dist/cli/commands/analytics/exporter.js +2 -2
- package/dist/cli/commands/analytics/exporter.js.map +1 -1
- package/dist/cli/commands/analytics/index.d.ts.map +1 -1
- package/dist/cli/commands/analytics/index.js +107 -10
- package/dist/cli/commands/analytics/index.js.map +1 -1
- package/dist/cli/commands/analytics/native-loader.d.ts +48 -0
- package/dist/cli/commands/analytics/native-loader.d.ts.map +1 -0
- package/dist/cli/commands/analytics/native-loader.js +220 -0
- package/dist/cli/commands/analytics/native-loader.js.map +1 -0
- package/dist/cli/commands/analytics/report/assets/chart.umd.js +14 -0
- package/dist/cli/commands/analytics/report/assets/codemie-bundle.css +1 -0
- package/dist/cli/commands/analytics/report/client/app.js +676 -0
- package/dist/cli/commands/analytics/report/payload-builder.d.ts +15 -0
- package/dist/cli/commands/analytics/report/payload-builder.d.ts.map +1 -0
- package/dist/cli/commands/analytics/report/payload-builder.js +107 -0
- package/dist/cli/commands/analytics/report/payload-builder.js.map +1 -0
- package/dist/cli/commands/analytics/report/report-generator.d.ts +47 -0
- package/dist/cli/commands/analytics/report/report-generator.d.ts.map +1 -0
- package/dist/cli/commands/analytics/report/report-generator.js +102 -0
- package/dist/cli/commands/analytics/report/report-generator.js.map +1 -0
- package/dist/cli/commands/analytics/report/template.html +217 -0
- package/dist/cli/commands/analytics/report/types.d.ts +55 -0
- package/dist/cli/commands/analytics/report/types.d.ts.map +1 -0
- package/dist/cli/commands/analytics/report/types.js +6 -0
- package/dist/cli/commands/analytics/report/types.js.map +1 -0
- package/dist/cli/commands/analytics/types.d.ts +13 -0
- package/dist/cli/commands/analytics/types.d.ts.map +1 -1
- package/dist/cli/commands/proxy/daemon-manager.d.ts +5 -0
- package/dist/cli/commands/proxy/daemon-manager.d.ts.map +1 -1
- package/dist/cli/commands/proxy/daemon-manager.js +25 -9
- package/dist/cli/commands/proxy/daemon-manager.js.map +1 -1
- package/dist/cli/commands/proxy/health-check.d.ts +16 -0
- package/dist/cli/commands/proxy/health-check.d.ts.map +1 -0
- package/dist/cli/commands/proxy/health-check.js +81 -0
- package/dist/cli/commands/proxy/health-check.js.map +1 -0
- package/dist/cli/commands/proxy/index.d.ts.map +1 -1
- package/dist/cli/commands/proxy/index.js +54 -4
- package/dist/cli/commands/proxy/index.js.map +1 -1
- package/dist/cli/commands/proxy/watcher.d.ts +31 -0
- package/dist/cli/commands/proxy/watcher.d.ts.map +1 -0
- package/dist/cli/commands/proxy/watcher.js +97 -0
- package/dist/cli/commands/proxy/watcher.js.map +1 -0
- package/dist/cli/commands/skills/setup/sync-plugin.d.ts +15 -0
- package/dist/cli/commands/skills/setup/sync-plugin.d.ts.map +1 -0
- package/dist/cli/commands/skills/setup/sync-plugin.js +63 -0
- package/dist/cli/commands/skills/setup/sync-plugin.js.map +1 -0
- package/dist/providers/plugins/sso/proxy/proxy-errors.js +2 -2
- package/dist/providers/plugins/sso/proxy/proxy-errors.js.map +1 -1
- package/dist/providers/plugins/sso/proxy/proxy-types.d.ts +6 -0
- package/dist/providers/plugins/sso/proxy/proxy-types.d.ts.map +1 -1
- package/dist/providers/plugins/sso/proxy/sso.proxy.d.ts +1 -0
- package/dist/providers/plugins/sso/proxy/sso.proxy.d.ts.map +1 -1
- package/dist/providers/plugins/sso/proxy/sso.proxy.js +39 -3
- package/dist/providers/plugins/sso/proxy/sso.proxy.js.map +1 -1
- package/dist/providers/plugins/sso/session/processors/metrics/metrics-aggregator.js +14 -4
- package/dist/providers/plugins/sso/session/processors/metrics/metrics-aggregator.js.map +1 -1
- package/dist/providers/plugins/sso/session/processors/metrics/metrics-post-processor.d.ts.map +1 -1
- package/dist/providers/plugins/sso/session/processors/metrics/metrics-post-processor.js +5 -0
- package/dist/providers/plugins/sso/session/processors/metrics/metrics-post-processor.js.map +1 -1
- package/dist/providers/plugins/sso/session/processors/metrics/metrics-types.d.ts +2 -0
- package/dist/providers/plugins/sso/session/processors/metrics/metrics-types.d.ts.map +1 -1
- package/package.json +1 -1
- package/scripts/copy-plugins.js +39 -0
|
@@ -44,10 +44,12 @@ const SCOPES = [
|
|
|
44
44
|
'ChannelMessage.Read.All', 'ChannelMessage.Send',
|
|
45
45
|
'OnlineMeetingTranscript.Read.All', 'OnlineMeetings.Read',
|
|
46
46
|
'People.Read', 'Contacts.Read', 'offline_access',
|
|
47
|
-
'Notes.Read', 'Notes.ReadWrite',
|
|
47
|
+
'Notes.Read', 'Notes.ReadWrite', 'OnlineMeetingAiInsight.Read.All', 'Tasks.ReadWrite',
|
|
48
|
+
'Group.Read.All',
|
|
48
49
|
].join(' ');
|
|
49
50
|
const CACHE_FILE = path.join(os.homedir(), '.ms_graph_token_cache.json');
|
|
50
51
|
const GRAPH_BASE = 'https://graph.microsoft.com/v1.0';
|
|
52
|
+
const GRAPH_BETA = 'https://graph.microsoft.com/beta';
|
|
51
53
|
const TIMEOUT_MS = 5 * 60 * 1000;
|
|
52
54
|
|
|
53
55
|
// ── HTTP Helpers ──────────────────────────────────────────────────────────────
|
|
@@ -112,6 +114,21 @@ async function graphPost(endpoint, token, body) {
|
|
|
112
114
|
return res.body ? JSON.parse(res.body) : {};
|
|
113
115
|
}
|
|
114
116
|
|
|
117
|
+
async function graphPatch(endpoint, token, body, extraHeaders = {}) {
|
|
118
|
+
const bodyStr = JSON.stringify(body);
|
|
119
|
+
const res = await httpsRequest(`${GRAPH_BASE}${endpoint}`, {
|
|
120
|
+
method: 'PATCH',
|
|
121
|
+
headers: {
|
|
122
|
+
Authorization: `Bearer ${token}`,
|
|
123
|
+
'Content-Type': 'application/json',
|
|
124
|
+
'Content-Length': Buffer.byteLength(bodyStr),
|
|
125
|
+
...extraHeaders,
|
|
126
|
+
},
|
|
127
|
+
}, bodyStr);
|
|
128
|
+
// Planner PATCH returns 204 with an empty body unless Prefer: return=representation is sent.
|
|
129
|
+
return res.body ? JSON.parse(res.body) : {};
|
|
130
|
+
}
|
|
131
|
+
|
|
115
132
|
function graphDownload(endpoint, token) {
|
|
116
133
|
function fetch(url, auth) {
|
|
117
134
|
return new Promise((resolve, reject) => {
|
|
@@ -342,6 +359,15 @@ function fmtDt(iso) {
|
|
|
342
359
|
catch { return (iso || '').slice(0, 16).replace('T', ' '); }
|
|
343
360
|
}
|
|
344
361
|
|
|
362
|
+
// Formats a Graph dateTimeTimeZone object ({ dateTime, timeZone }). To Do returns a
|
|
363
|
+
// zone-less dateTime, so a UTC value would otherwise be parsed as local time by fmtDt.
|
|
364
|
+
function fmtDtTz(dtz) {
|
|
365
|
+
if (!dtz?.dateTime) return 'N/A';
|
|
366
|
+
let s = dtz.dateTime;
|
|
367
|
+
if (!/[zZ]|[+-]\d{2}:\d{2}$/.test(s) && (dtz.timeZone || '').toUpperCase() === 'UTC') s += 'Z';
|
|
368
|
+
return fmtDt(s);
|
|
369
|
+
}
|
|
370
|
+
|
|
345
371
|
function fmtSize(n) {
|
|
346
372
|
if (!n) return '';
|
|
347
373
|
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
@@ -750,9 +776,135 @@ async function cmdChannels(args) {
|
|
|
750
776
|
console.log(' --team-id ID --channel-id ID --send MSG');
|
|
751
777
|
}
|
|
752
778
|
|
|
779
|
+
// ── Meeting AI Insights (Copilot recap) ────────────────────────────────────────
|
|
780
|
+
// Lives in the Microsoft 365 Copilot API namespace and is keyed by user object ID
|
|
781
|
+
// (not /me). The aiInsights navigation is documented under beta, so try v1.0 first
|
|
782
|
+
// and fall back to beta on 404. Requires a Microsoft 365 Copilot license.
|
|
783
|
+
async function getAiInsights(token, oid, meetingId, insightId) {
|
|
784
|
+
const suffix = insightId ? `/${insightId}` : '';
|
|
785
|
+
const ep = `/copilot/users/${oid}/onlineMeetings/${meetingId}/aiInsights${suffix}`;
|
|
786
|
+
const headers = { Authorization: `Bearer ${token}` };
|
|
787
|
+
try {
|
|
788
|
+
const res = await httpsRequest(`${GRAPH_BASE}${ep}`, { headers });
|
|
789
|
+
return JSON.parse(res.body);
|
|
790
|
+
} catch (err) {
|
|
791
|
+
if (err.statusCode === 404) {
|
|
792
|
+
const res = await httpsRequest(`${GRAPH_BETA}${ep}`, { headers });
|
|
793
|
+
return JSON.parse(res.body);
|
|
794
|
+
}
|
|
795
|
+
throw err;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
async function printMeetingInsights(token, oid, meetingId, args) {
|
|
800
|
+
let list;
|
|
801
|
+
try {
|
|
802
|
+
list = await getAiInsights(token, oid, meetingId);
|
|
803
|
+
} catch (err) {
|
|
804
|
+
if (err.statusCode === 403) {
|
|
805
|
+
console.error('AI insights require a Microsoft 365 Copilot license (and transcription/recording enabled for the meeting).');
|
|
806
|
+
return;
|
|
807
|
+
}
|
|
808
|
+
if (err.statusCode === 404) {
|
|
809
|
+
console.log('No AI insights available for this meeting (none generated yet, or unsupported meeting type).');
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
throw err;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
const insights = list.value || [];
|
|
816
|
+
if (!insights.length) {
|
|
817
|
+
console.log('No AI insights yet. Insights generate after the meeting ends and can take up to 4 hours.');
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
const full = [];
|
|
822
|
+
for (const ins of insights) {
|
|
823
|
+
try { full.push(await getAiInsights(token, oid, meetingId, ins.id)); }
|
|
824
|
+
catch { full.push(ins); }
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
if (args.json) { console.log(JSON.stringify(full, null, 2)); return; }
|
|
828
|
+
|
|
829
|
+
for (const ai of full) {
|
|
830
|
+
console.log(`\n${'═'.repeat(60)}`);
|
|
831
|
+
console.log(`AI Insight ${ai.id || ''} (${fmtDt(ai.createdDateTime)})`);
|
|
832
|
+
|
|
833
|
+
const notes = ai.meetingNotes || [];
|
|
834
|
+
if (notes.length) {
|
|
835
|
+
console.log('\nMeeting Notes:');
|
|
836
|
+
for (const n of notes) {
|
|
837
|
+
console.log(` • ${n.title || ''}`);
|
|
838
|
+
if (n.text) console.log(` ${n.text}`);
|
|
839
|
+
for (const sp of n.subpoints || []) {
|
|
840
|
+
console.log(` – ${sp.title || ''}`);
|
|
841
|
+
if (sp.text) console.log(` ${sp.text}`);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
const items = ai.actionItems || [];
|
|
847
|
+
if (items.length) {
|
|
848
|
+
console.log('\nAction Items:');
|
|
849
|
+
for (const it of items)
|
|
850
|
+
console.log(` ☐ ${it.title || ''}${it.ownerDisplayName ? ` (owner: ${it.ownerDisplayName})` : ''}`);
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
const mentions = ai.viewpoint?.mentionEvents || [];
|
|
854
|
+
if (mentions.length) {
|
|
855
|
+
console.log('\nMentions:');
|
|
856
|
+
for (const m of mentions)
|
|
857
|
+
console.log(` @ ${fmtDt(m.eventDateTime)} ${m.speaker?.user?.displayName || ''}: ${(m.transcriptUtterance || '').slice(0, 200)}`);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
async function cmdTranscriptsInsights(args, token) {
|
|
863
|
+
const me = await graphGet('/me', token, { $select: 'id' });
|
|
864
|
+
const oid = me.id;
|
|
865
|
+
|
|
866
|
+
// Direct meeting ID short-circuits resolution.
|
|
867
|
+
if (args.meeting) {
|
|
868
|
+
await printMeetingInsights(token, oid, args.meeting, args);
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
// Otherwise resolve online meetings via the calendar (same approach as --subject).
|
|
873
|
+
const startDate = args.start || new Date(Date.now() - 7 * 86400 * 1000).toISOString().slice(0, 10);
|
|
874
|
+
const endDate = args.end || startDate;
|
|
875
|
+
const data = await graphGet('/me/calendarView', token, {
|
|
876
|
+
startDateTime: startDate + 'T00:00:00Z',
|
|
877
|
+
endDateTime: endDate + 'T23:59:59Z',
|
|
878
|
+
$select: 'subject,start,isOnlineMeeting,onlineMeeting',
|
|
879
|
+
$top: 50,
|
|
880
|
+
$orderby: 'start/dateTime',
|
|
881
|
+
});
|
|
882
|
+
let events = (data.value || []).filter(e => e.isOnlineMeeting && e.onlineMeeting?.joinUrl);
|
|
883
|
+
if (args.subject) {
|
|
884
|
+
const kw = args.subject.toLowerCase();
|
|
885
|
+
events = events.filter(e => (e.subject || '').toLowerCase().includes(kw));
|
|
886
|
+
}
|
|
887
|
+
if (!events.length) { console.log('No matching online meetings found in range.'); return; }
|
|
888
|
+
|
|
889
|
+
for (const e of events) {
|
|
890
|
+
let meetingId = null;
|
|
891
|
+
try {
|
|
892
|
+
const om = await graphGet('/me/onlineMeetings', token, { $filter: `joinWebUrl eq '${e.onlineMeeting.joinUrl}'` });
|
|
893
|
+
meetingId = (om.value || [])[0]?.id || null;
|
|
894
|
+
} catch (err) {
|
|
895
|
+
console.log(`Could not resolve meeting ID for "${e.subject}": ${err.message}`);
|
|
896
|
+
}
|
|
897
|
+
if (!meetingId) continue;
|
|
898
|
+
console.log(`\nMeeting: ${e.subject} (${fmtDt(e.start?.dateTime)}) — ${meetingId}`);
|
|
899
|
+
await printMeetingInsights(token, oid, meetingId, args);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
|
|
753
903
|
async function cmdTranscripts(args) {
|
|
754
904
|
const token = await getValidToken();
|
|
755
905
|
|
|
906
|
+
if (args.insights) return cmdTranscriptsInsights(args, token);
|
|
907
|
+
|
|
756
908
|
if (args.list || (!args.meeting && !args.download)) {
|
|
757
909
|
const startDate = args.start || new Date(Date.now() - 7 * 86400 * 1000).toISOString().slice(0, 10);
|
|
758
910
|
const endDate = args.end || startDate;
|
|
@@ -1161,10 +1313,179 @@ async function cmdOnenote(args) {
|
|
|
1161
1313
|
console.log(' --create TITLE --section SECTION_ID [--body CONTENT]');
|
|
1162
1314
|
}
|
|
1163
1315
|
|
|
1316
|
+
async function cmdPlanner(args) {
|
|
1317
|
+
const token = await getValidToken();
|
|
1318
|
+
const limit = parseInt(args.limit) || 20;
|
|
1319
|
+
|
|
1320
|
+
// Plans shared with me (single call; plans live in M365 groups → needs Group.Read.All).
|
|
1321
|
+
// Planner rejects OData params ($top/$select/$filter return HTTP 400) — fetch all, slice client-side.
|
|
1322
|
+
if (args.plans) {
|
|
1323
|
+
const data = await graphGet('/me/planner/plans', token);
|
|
1324
|
+
const plans = (data.value || []).slice(0, limit);
|
|
1325
|
+
if (args.json) { console.log(JSON.stringify(plans, null, 2)); return; }
|
|
1326
|
+
if (!plans.length) { console.log('No plans found.'); return; }
|
|
1327
|
+
console.log(`\n${'Plan ID'.padEnd(30)} Title`);
|
|
1328
|
+
console.log('─'.repeat(70));
|
|
1329
|
+
for (const p of plans)
|
|
1330
|
+
console.log(`${(p.id || '').padEnd(30)} ${p.title || '(untitled)'}`);
|
|
1331
|
+
return;
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
// Tasks assigned to me (returns planId/bucketId only — no names). No OData params on Planner.
|
|
1335
|
+
if (args.myTasks) {
|
|
1336
|
+
const data = await graphGet('/me/planner/tasks', token);
|
|
1337
|
+
const tasks = (data.value || []).slice(0, limit);
|
|
1338
|
+
if (args.json) { console.log(JSON.stringify(tasks, null, 2)); return; }
|
|
1339
|
+
if (!tasks.length) { console.log('No tasks assigned to you.'); return; }
|
|
1340
|
+
console.log(`\n${'Task ID'.padEnd(30)} ${'%'.padEnd(4)} ${'Due'.padEnd(16)} Title`);
|
|
1341
|
+
console.log('─'.repeat(80));
|
|
1342
|
+
for (const t of tasks) {
|
|
1343
|
+
const due = t.dueDateTime ? fmtDt(t.dueDateTime) : '';
|
|
1344
|
+
console.log(`${(t.id || '').padEnd(30)} ${String(t.percentComplete ?? 0).padEnd(4)} ${pad(due, 16)} ${t.title || '(untitled)'}`);
|
|
1345
|
+
}
|
|
1346
|
+
return;
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
// Buckets (columns) in a plan.
|
|
1350
|
+
if (args.planId && args.buckets) {
|
|
1351
|
+
const data = await graphGet(`/planner/plans/${args.planId}/buckets`, token);
|
|
1352
|
+
const buckets = data.value || [];
|
|
1353
|
+
if (args.json) { console.log(JSON.stringify(buckets, null, 2)); return; }
|
|
1354
|
+
if (!buckets.length) { console.log('No buckets found.'); return; }
|
|
1355
|
+
console.log(`\n${'Bucket ID'.padEnd(30)} Name`);
|
|
1356
|
+
console.log('─'.repeat(70));
|
|
1357
|
+
for (const b of buckets)
|
|
1358
|
+
console.log(`${(b.id || '').padEnd(30)} ${b.name || '(unnamed)'}`);
|
|
1359
|
+
return;
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
// Create a task in a plan.
|
|
1363
|
+
if (args.planId && typeof args.create === 'string') {
|
|
1364
|
+
const payload = { planId: args.planId, title: args.create };
|
|
1365
|
+
if (args.bucketId) payload.bucketId = args.bucketId;
|
|
1366
|
+
if (args.due) payload.dueDateTime = `${args.due}T00:00:00Z`;
|
|
1367
|
+
if (args.assign) {
|
|
1368
|
+
payload.assignments = {
|
|
1369
|
+
[args.assign]: { '@odata.type': '#microsoft.graph.plannerAssignment', orderHint: ' !' },
|
|
1370
|
+
};
|
|
1371
|
+
}
|
|
1372
|
+
const task = await graphPost('/planner/tasks', token, payload);
|
|
1373
|
+
console.log(`Task created: ${task.title || args.create}`);
|
|
1374
|
+
console.log(`ID: ${task.id}`);
|
|
1375
|
+
return;
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
// Tasks in a plan. No OData params on Planner.
|
|
1379
|
+
if (args.planId && args.tasks) {
|
|
1380
|
+
const data = await graphGet(`/planner/plans/${args.planId}/tasks`, token);
|
|
1381
|
+
const tasks = (data.value || []).slice(0, limit);
|
|
1382
|
+
if (args.json) { console.log(JSON.stringify(tasks, null, 2)); return; }
|
|
1383
|
+
if (!tasks.length) { console.log('No tasks in this plan.'); return; }
|
|
1384
|
+
console.log(`\n${'Task ID'.padEnd(30)} ${'%'.padEnd(4)} ${'Due'.padEnd(16)} Title`);
|
|
1385
|
+
console.log('─'.repeat(80));
|
|
1386
|
+
for (const t of tasks) {
|
|
1387
|
+
const due = t.dueDateTime ? fmtDt(t.dueDateTime) : '';
|
|
1388
|
+
console.log(`${(t.id || '').padEnd(30)} ${String(t.percentComplete ?? 0).padEnd(4)} ${pad(due, 16)} ${t.title || '(untitled)'}`);
|
|
1389
|
+
}
|
|
1390
|
+
return;
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
// Mark a task complete: read its etag, then PATCH percentComplete to 100.
|
|
1394
|
+
if (typeof args.complete === 'string') {
|
|
1395
|
+
const task = await graphGet(`/planner/tasks/${args.complete}`, token);
|
|
1396
|
+
const etag = task['@odata.etag'];
|
|
1397
|
+
if (!etag) { console.error('Could not read the task etag; cannot update.'); process.exit(1); }
|
|
1398
|
+
await graphPatch(`/planner/tasks/${args.complete}`, token, { percentComplete: 100 }, { 'If-Match': etag });
|
|
1399
|
+
console.log(`Task marked complete: ${task.title || args.complete}`);
|
|
1400
|
+
return;
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
// Single task detail (+ description/checklist from /details).
|
|
1404
|
+
if (args.taskId) {
|
|
1405
|
+
const task = await graphGet(`/planner/tasks/${args.taskId}`, token);
|
|
1406
|
+
let details = {};
|
|
1407
|
+
try { details = await graphGet(`/planner/tasks/${args.taskId}/details`, token); } catch {}
|
|
1408
|
+
if (args.json) { console.log(JSON.stringify({ ...task, details }, null, 2)); return; }
|
|
1409
|
+
console.log(`Title : ${task.title || '(untitled)'}`);
|
|
1410
|
+
console.log(`% Complete : ${task.percentComplete ?? 0}`);
|
|
1411
|
+
console.log(`Due : ${task.dueDateTime ? fmtDt(task.dueDateTime) : 'N/A'}`);
|
|
1412
|
+
console.log(`Bucket ID : ${task.bucketId || 'N/A'}`);
|
|
1413
|
+
console.log(`Plan ID : ${task.planId || 'N/A'}`);
|
|
1414
|
+
if (details.description) console.log(`\nDescription:\n${details.description}`);
|
|
1415
|
+
return;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
console.log('Planner: --plans | --my-tasks');
|
|
1419
|
+
console.log(' --plan-id ID --tasks | --plan-id ID --buckets');
|
|
1420
|
+
console.log(' --plan-id ID --create "TITLE" [--bucket-id ID] [--due YYYY-MM-DD] [--assign USER_ID]');
|
|
1421
|
+
console.log(' --task-id ID | --complete TASK_ID');
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
async function cmdTodo(args) {
|
|
1425
|
+
const token = await getValidToken();
|
|
1426
|
+
const limit = parseInt(args.limit) || 20;
|
|
1427
|
+
|
|
1428
|
+
if (args.lists) {
|
|
1429
|
+
const data = await graphGet('/me/todo/lists', token, { $top: limit });
|
|
1430
|
+
const lists = data.value || [];
|
|
1431
|
+
if (args.json) { console.log(JSON.stringify(lists, null, 2)); return; }
|
|
1432
|
+
if (!lists.length) { console.log('No task lists found.'); return; }
|
|
1433
|
+
console.log(`\n${'List ID'.padEnd(50)} Name`);
|
|
1434
|
+
console.log('─'.repeat(80));
|
|
1435
|
+
for (const l of lists)
|
|
1436
|
+
console.log(`${(l.id || '').padEnd(50)} ${l.displayName || '(unnamed)'}`);
|
|
1437
|
+
return;
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
if (!args.listId) {
|
|
1441
|
+
console.log('To Do: --lists');
|
|
1442
|
+
console.log(' --list-id ID --tasks');
|
|
1443
|
+
console.log(' --list-id ID --create "TITLE" [--body TEXT] [--due YYYY-MM-DD]');
|
|
1444
|
+
console.log(' --list-id ID --complete TASK_ID');
|
|
1445
|
+
return;
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
// Create a task in a list.
|
|
1449
|
+
if (typeof args.create === 'string') {
|
|
1450
|
+
const payload = { title: args.create };
|
|
1451
|
+
if (args.body) payload.body = { content: args.body, contentType: 'text' };
|
|
1452
|
+
if (args.due) payload.dueDateTime = { dateTime: `${args.due}T00:00:00.000000`, timeZone: 'UTC' };
|
|
1453
|
+
const task = await graphPost(`/me/todo/lists/${args.listId}/tasks`, token, payload);
|
|
1454
|
+
console.log(`Task created: ${task.title || args.create}`);
|
|
1455
|
+
console.log(`ID: ${task.id}`);
|
|
1456
|
+
return;
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
// Mark a task complete (To Do needs no etag).
|
|
1460
|
+
if (typeof args.complete === 'string') {
|
|
1461
|
+
await graphPatch(`/me/todo/lists/${args.listId}/tasks/${args.complete}`, token, { status: 'completed' });
|
|
1462
|
+
console.log(`Task marked complete: ${args.complete}`);
|
|
1463
|
+
return;
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
// Tasks in a list.
|
|
1467
|
+
if (args.tasks) {
|
|
1468
|
+
const data = await graphGet(`/me/todo/lists/${args.listId}/tasks`, token, { $top: limit });
|
|
1469
|
+
const tasks = data.value || [];
|
|
1470
|
+
if (args.json) { console.log(JSON.stringify(tasks, null, 2)); return; }
|
|
1471
|
+
if (!tasks.length) { console.log('No tasks in this list.'); return; }
|
|
1472
|
+
console.log(`\n${'Task ID'.padEnd(50)} ${'Status'.padEnd(12)} Title`);
|
|
1473
|
+
console.log('─'.repeat(80));
|
|
1474
|
+
for (const t of tasks) {
|
|
1475
|
+
const due = t.dueDateTime?.dateTime ? ` (due ${fmtDtTz(t.dueDateTime)})` : '';
|
|
1476
|
+
console.log(`${(t.id || '').padEnd(50)} ${(t.status || '').padEnd(12)} ${t.title || '(untitled)'}${due}`);
|
|
1477
|
+
}
|
|
1478
|
+
return;
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
console.log('To Do: --list-id ID --tasks | --create "TITLE" | --complete TASK_ID');
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1164
1484
|
// ── CLI Parser ────────────────────────────────────────────────────────────────
|
|
1165
1485
|
function parseArgs(argv) {
|
|
1166
1486
|
const BOOL = new Set(['json','unread','sites','chats','teamsList','contacts',
|
|
1167
|
-
'manager','reports','availability','notebooks','list','messages','vtt','help','force'
|
|
1487
|
+
'manager','reports','availability','notebooks','list','messages','vtt','help','force',
|
|
1488
|
+
'plans','buckets','tasks','myTasks','lists','insights']);
|
|
1168
1489
|
const args = { _: [] };
|
|
1169
1490
|
let i = 0;
|
|
1170
1491
|
while (i < argv.length) {
|
|
@@ -1216,8 +1537,16 @@ Data:
|
|
|
1216
1537
|
onenote [--notebooks] [--sections NOTEBOOK_ID] [--pages SECTION_ID]
|
|
1217
1538
|
[--read PAGE_ID] [--search QUERY] [--limit N] [--json]
|
|
1218
1539
|
[--create TITLE --section SECTION_ID [--body CONTENT]]
|
|
1540
|
+
planner [--plans] [--my-tasks]
|
|
1541
|
+
[--plan-id ID --tasks] [--plan-id ID --buckets]
|
|
1542
|
+
[--plan-id ID --create "TITLE" [--bucket-id ID] [--due YYYY-MM-DD] [--assign USER_ID]]
|
|
1543
|
+
[--task-id ID] [--complete TASK_ID] [--json]
|
|
1544
|
+
todo [--lists] [--list-id ID --tasks]
|
|
1545
|
+
[--list-id ID --create "TITLE" [--body TEXT] [--due YYYY-MM-DD]]
|
|
1546
|
+
[--list-id ID --complete TASK_ID] [--json]
|
|
1219
1547
|
transcripts [--start YYYY-MM-DD] [--end YYYY-MM-DD] [--subject KEYWORD]
|
|
1220
1548
|
[--meeting ID] [--transcript ID] [--output FILE] [--vtt]
|
|
1549
|
+
[--insights] (AI meeting recap — requires Microsoft 365 Copilot)
|
|
1221
1550
|
|
|
1222
1551
|
Add --json to any command for machine-readable output.
|
|
1223
1552
|
`);
|
|
@@ -1245,6 +1574,8 @@ async function main() {
|
|
|
1245
1574
|
people: () => cmdPeople(args),
|
|
1246
1575
|
org: () => cmdOrg(args),
|
|
1247
1576
|
onenote: () => cmdOnenote(args),
|
|
1577
|
+
planner: () => cmdPlanner(args),
|
|
1578
|
+
todo: () => cmdTodo(args),
|
|
1248
1579
|
transcripts: () => cmdTranscripts(args),
|
|
1249
1580
|
claims: () => cmdClaims(args),
|
|
1250
1581
|
help: () => { printHelp(); process.exit(0); },
|
|
@@ -20,10 +20,18 @@ const ENCRYPTION_KEY = (() => {
|
|
|
20
20
|
})();
|
|
21
21
|
|
|
22
22
|
function decrypt(text) {
|
|
23
|
-
const
|
|
24
|
-
|
|
23
|
+
const parts = text.split(':');
|
|
24
|
+
if (parts.length === 3) {
|
|
25
|
+
const iv = Buffer.from(parts[0], 'hex');
|
|
26
|
+
const authTag = Buffer.from(parts[1], 'hex');
|
|
27
|
+
const d = crypto.createDecipheriv('aes-256-gcm', ENCRYPTION_KEY, iv);
|
|
28
|
+
d.setAuthTag(authTag);
|
|
29
|
+
return d.update(parts[2], 'hex', 'utf8') + d.final('utf8');
|
|
30
|
+
}
|
|
31
|
+
// Legacy CBC format: iv:encrypted (backward compat for existing stored credentials)
|
|
32
|
+
const iv = Buffer.from(parts[0], 'hex');
|
|
25
33
|
const d = crypto.createDecipheriv('aes-256-cbc', ENCRYPTION_KEY, iv);
|
|
26
|
-
return d.update(
|
|
34
|
+
return d.update(parts[1], 'hex', 'utf8') + d.final('utf8');
|
|
27
35
|
}
|
|
28
36
|
|
|
29
37
|
function urlHash(rawUrl) {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Claude file-operation extraction.
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for turning a Claude tool call (tool name + input + the user
|
|
5
|
+
* message's `toolUseResult`) into a file-operation record with line counts. Used by both
|
|
6
|
+
* the live {@link MetricsProcessor} and the session adapter's parse path, so re-parsed
|
|
7
|
+
* (native, untracked) sessions report the same `linesAdded`/`linesRemoved` as live-tracked ones.
|
|
8
|
+
*/
|
|
9
|
+
export interface ClaudeFileOperation {
|
|
10
|
+
type: string;
|
|
11
|
+
path?: string;
|
|
12
|
+
format?: string;
|
|
13
|
+
language?: string;
|
|
14
|
+
pattern?: string;
|
|
15
|
+
linesAdded?: number;
|
|
16
|
+
linesRemoved?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Build a file-operation record for a Claude tool call, or `undefined` if the tool is not a
|
|
20
|
+
* file/search tool. Line counts come from the Write content or the Edit `structuredPatch`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function extractClaudeFileOperation(toolName: string, input?: {
|
|
23
|
+
file_path?: string;
|
|
24
|
+
path?: string;
|
|
25
|
+
content?: string;
|
|
26
|
+
pattern?: string;
|
|
27
|
+
} | unknown, toolUseResult?: {
|
|
28
|
+
filePath?: string;
|
|
29
|
+
file?: {
|
|
30
|
+
filePath?: string;
|
|
31
|
+
content?: string;
|
|
32
|
+
};
|
|
33
|
+
content?: string;
|
|
34
|
+
structuredPatch?: Array<{
|
|
35
|
+
lines?: unknown[];
|
|
36
|
+
}>;
|
|
37
|
+
} | unknown): ClaudeFileOperation | undefined;
|
|
38
|
+
//# sourceMappingURL=claude-file-operation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-file-operation.d.ts","sourceRoot":"","sources":["../../../../../src/agents/plugins/claude/session/claude-file-operation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAWD;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,EAC3F,aAAa,CAAC,EACV;IACE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,CAAC,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC,CAAC;CAChD,GACD,OAAO,GACV,mBAAmB,GAAG,SAAS,CAgDjC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Claude file-operation extraction.
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for turning a Claude tool call (tool name + input + the user
|
|
5
|
+
* message's `toolUseResult`) into a file-operation record with line counts. Used by both
|
|
6
|
+
* the live {@link MetricsProcessor} and the session adapter's parse path, so re-parsed
|
|
7
|
+
* (native, untracked) sessions report the same `linesAdded`/`linesRemoved` as live-tracked ones.
|
|
8
|
+
*/
|
|
9
|
+
import { extractFormat, detectLanguage } from '../../../../utils/file-operations.js';
|
|
10
|
+
/** Tool names that map to a file operation, and their operation type. */
|
|
11
|
+
const TOOL_TYPE_MAP = {
|
|
12
|
+
Read: 'read',
|
|
13
|
+
Write: 'write',
|
|
14
|
+
Edit: 'edit',
|
|
15
|
+
Grep: 'grep',
|
|
16
|
+
Glob: 'glob',
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Build a file-operation record for a Claude tool call, or `undefined` if the tool is not a
|
|
20
|
+
* file/search tool. Line counts come from the Write content or the Edit `structuredPatch`.
|
|
21
|
+
*/
|
|
22
|
+
export function extractClaudeFileOperation(toolName, input, toolUseResult) {
|
|
23
|
+
const type = TOOL_TYPE_MAP[toolName];
|
|
24
|
+
if (!type) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
const inp = (input ?? {});
|
|
28
|
+
const res = (toolUseResult ?? {});
|
|
29
|
+
const fileOp = { type };
|
|
30
|
+
const filePath = res.filePath || res.file?.filePath || inp.file_path || inp.path;
|
|
31
|
+
if (filePath) {
|
|
32
|
+
fileOp.path = filePath;
|
|
33
|
+
fileOp.format = extractFormat(filePath);
|
|
34
|
+
fileOp.language = detectLanguage(filePath);
|
|
35
|
+
}
|
|
36
|
+
else if (inp.pattern) {
|
|
37
|
+
fileOp.pattern = inp.pattern;
|
|
38
|
+
}
|
|
39
|
+
if (toolName === 'Write') {
|
|
40
|
+
const content = res.content || res.file?.content || inp.content;
|
|
41
|
+
if (content) {
|
|
42
|
+
fileOp.linesAdded = content.split('\n').length;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else if (toolName === 'Edit' && Array.isArray(res.structuredPatch)) {
|
|
46
|
+
let added = 0;
|
|
47
|
+
let removed = 0;
|
|
48
|
+
for (const patch of res.structuredPatch) {
|
|
49
|
+
if (Array.isArray(patch.lines)) {
|
|
50
|
+
for (const line of patch.lines) {
|
|
51
|
+
if (typeof line === 'string') {
|
|
52
|
+
if (line.startsWith('+'))
|
|
53
|
+
added++;
|
|
54
|
+
else if (line.startsWith('-'))
|
|
55
|
+
removed++;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (added > 0)
|
|
61
|
+
fileOp.linesAdded = added;
|
|
62
|
+
if (removed > 0)
|
|
63
|
+
fileOp.linesRemoved = removed;
|
|
64
|
+
}
|
|
65
|
+
return fileOp;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=claude-file-operation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-file-operation.js","sourceRoot":"","sources":["../../../../../src/agents/plugins/claude/session/claude-file-operation.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAYrF,yEAAyE;AACzE,MAAM,aAAa,GAA2B;IAC5C,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;CACb,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,0BAA0B,CACxC,QAAgB,EAChB,KAA2F,EAC3F,aAOW;IAEX,MAAM,IAAI,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IACrC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,GAAG,GAAG,CAAC,KAAK,IAAI,EAAE,CAA8E,CAAC;IACvG,MAAM,GAAG,GAAG,CAAC,aAAa,IAAI,EAAE,CAK/B,CAAC;IAEF,MAAM,MAAM,GAAwB,EAAE,IAAI,EAAE,CAAC;IAE7C,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,IAAI,EAAE,QAAQ,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,IAAI,CAAC;IACjF,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,GAAG,QAAQ,CAAC;QACvB,MAAM,CAAC,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;QACxC,MAAM,CAAC,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC7C,CAAC;SAAM,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;QACvB,MAAM,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;IAC/B,CAAC;IAED,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,IAAI,EAAE,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC;QAChE,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;QACjD,CAAC;IACH,CAAC;SAAM,IAAI,QAAQ,KAAK,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;QACrE,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,eAAe,EAAE,CAAC;YACxC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;oBAC/B,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;wBAC7B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;4BAAE,KAAK,EAAE,CAAC;6BAC7B,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;4BAAE,OAAO,EAAE,CAAC;oBAC3C,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QACD,IAAI,KAAK,GAAG,CAAC;YAAE,MAAM,CAAC,UAAU,GAAG,KAAK,CAAC;QACzC,IAAI,OAAO,GAAG,CAAC;YAAE,MAAM,CAAC,YAAY,GAAG,OAAO,CAAC;IACjD,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -31,9 +31,5 @@ export declare class MetricsProcessor implements SessionProcessor {
|
|
|
31
31
|
private extractDeltasFromMessages;
|
|
32
32
|
private isToolResultMessage;
|
|
33
33
|
private isSyntheticUserPrompt;
|
|
34
|
-
/**
|
|
35
|
-
* Extract file operation from tool call (simplified version of legacy logic)
|
|
36
|
-
*/
|
|
37
|
-
private extractFileOperation;
|
|
38
34
|
}
|
|
39
35
|
//# sourceMappingURL=claude.metrics-processor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude.metrics-processor.d.ts","sourceRoot":"","sources":["../../../../../../src/agents/plugins/claude/session/processors/claude.metrics-processor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AACvH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gDAAgD,CAAC;AAKpF,qBAAa,gBAAiB,YAAW,gBAAgB;IACvD,QAAQ,CAAC,IAAI,aAAa;IAC1B,QAAQ,CAAC,QAAQ,KAAK;IAEtB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO;IAIxC,OAAO,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAY5F;;OAEG;YACW,eAAe;IAqE7B;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAiCjC;;OAEG;IACH,OAAO,CAAC,yBAAyB;
|
|
1
|
+
{"version":3,"file":"claude.metrics-processor.d.ts","sourceRoot":"","sources":["../../../../../../src/agents/plugins/claude/session/processors/claude.metrics-processor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AACvH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gDAAgD,CAAC;AAKpF,qBAAa,gBAAiB,YAAW,gBAAgB;IACvD,QAAQ,CAAC,IAAI,aAAa;IAC1B,QAAQ,CAAC,QAAQ,KAAK;IAEtB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO;IAIxC,OAAO,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAY5F;;OAEG;YACW,eAAe;IAqE7B;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAiCjC;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAuMjC,OAAO,CAAC,mBAAmB;IAS3B,OAAO,CAAC,qBAAqB;CAS9B"}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* Note: API sync is handled separately by SSO provider's MetricsSyncProcessor
|
|
12
12
|
*/
|
|
13
13
|
import { logger } from '../../../../../utils/logger.js';
|
|
14
|
-
import {
|
|
14
|
+
import { extractClaudeFileOperation } from '../claude-file-operation.js';
|
|
15
15
|
export class MetricsProcessor {
|
|
16
16
|
name = 'metrics';
|
|
17
17
|
priority = 1; // Run first
|
|
@@ -227,7 +227,7 @@ export class MetricsProcessor {
|
|
|
227
227
|
toolStatus[toolName].success++;
|
|
228
228
|
// Extract file operations
|
|
229
229
|
const toolUseResult = toolUseResultMap.get(block.id);
|
|
230
|
-
const fileOp =
|
|
230
|
+
const fileOp = extractClaudeFileOperation(toolName, block.input, toolUseResult);
|
|
231
231
|
if (fileOp) {
|
|
232
232
|
fileOperations.push(fileOp);
|
|
233
233
|
}
|
|
@@ -237,6 +237,9 @@ export class MetricsProcessor {
|
|
|
237
237
|
}
|
|
238
238
|
}
|
|
239
239
|
const recordId = messages[0].uuid;
|
|
240
|
+
const apiErrorMessage = completedMsg.isApiErrorMessage && completedMsg.message?.content?.[0]?.text
|
|
241
|
+
? completedMsg.message.content[0].text
|
|
242
|
+
: undefined;
|
|
240
243
|
const delta = {
|
|
241
244
|
recordId,
|
|
242
245
|
sessionId,
|
|
@@ -245,7 +248,8 @@ export class MetricsProcessor {
|
|
|
245
248
|
gitBranch: completedMsg.gitBranch,
|
|
246
249
|
...(Object.keys(tools).length > 0 && { tools }),
|
|
247
250
|
...(Object.keys(toolStatus).length > 0 && { toolStatus }),
|
|
248
|
-
...(completedMsg.message?.model && { models: [completedMsg.message.model] })
|
|
251
|
+
...(completedMsg.message?.model && { models: [completedMsg.message.model] }),
|
|
252
|
+
...(apiErrorMessage && { apiErrorMessage })
|
|
249
253
|
};
|
|
250
254
|
if (fileOperations.length > 0) {
|
|
251
255
|
delta.fileOperations = fileOperations;
|
|
@@ -285,58 +289,5 @@ export class MetricsProcessor {
|
|
|
285
289
|
const parent = messagesByUuid.get(msg.parentUuid);
|
|
286
290
|
return this.isToolResultMessage(parent);
|
|
287
291
|
}
|
|
288
|
-
/**
|
|
289
|
-
* Extract file operation from tool call (simplified version of legacy logic)
|
|
290
|
-
*/
|
|
291
|
-
extractFileOperation(toolName, input, toolUseResult) {
|
|
292
|
-
const typeMap = {
|
|
293
|
-
'Read': 'read',
|
|
294
|
-
'Write': 'write',
|
|
295
|
-
'Edit': 'edit',
|
|
296
|
-
'Grep': 'grep',
|
|
297
|
-
'Glob': 'glob'
|
|
298
|
-
};
|
|
299
|
-
const type = typeMap[toolName];
|
|
300
|
-
if (!type)
|
|
301
|
-
return undefined;
|
|
302
|
-
const fileOp = { type };
|
|
303
|
-
const filePath = toolUseResult?.filePath || toolUseResult?.file?.filePath || input?.file_path || input?.path;
|
|
304
|
-
if (filePath) {
|
|
305
|
-
fileOp.path = filePath;
|
|
306
|
-
fileOp.format = extractFormat(filePath);
|
|
307
|
-
fileOp.language = detectLanguage(filePath);
|
|
308
|
-
}
|
|
309
|
-
else if (input?.pattern) {
|
|
310
|
-
fileOp.pattern = input.pattern;
|
|
311
|
-
}
|
|
312
|
-
if (toolName === 'Write') {
|
|
313
|
-
const content = toolUseResult?.content || toolUseResult?.file?.content || input?.content;
|
|
314
|
-
if (content) {
|
|
315
|
-
const lines = content.split('\n');
|
|
316
|
-
fileOp.linesAdded = lines.length;
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
else if (toolName === 'Edit' && toolUseResult?.structuredPatch) {
|
|
320
|
-
let added = 0;
|
|
321
|
-
let removed = 0;
|
|
322
|
-
for (const patch of toolUseResult.structuredPatch) {
|
|
323
|
-
if (Array.isArray(patch.lines)) {
|
|
324
|
-
for (const line of patch.lines) {
|
|
325
|
-
if (typeof line === 'string') {
|
|
326
|
-
if (line.startsWith('+'))
|
|
327
|
-
added++;
|
|
328
|
-
else if (line.startsWith('-'))
|
|
329
|
-
removed++;
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
if (added > 0)
|
|
335
|
-
fileOp.linesAdded = added;
|
|
336
|
-
if (removed > 0)
|
|
337
|
-
fileOp.linesRemoved = removed;
|
|
338
|
-
}
|
|
339
|
-
return fileOp;
|
|
340
|
-
}
|
|
341
292
|
}
|
|
342
293
|
//# sourceMappingURL=claude.metrics-processor.js.map
|