@commandgarden/cli 2.5.1 → 2.6.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/node_modules/@commandgarden/app/dist/client/assets/index-Dm4TTmUS.css +1 -0
- package/node_modules/@commandgarden/app/dist/client/assets/index-tVkaaa2g.js +421 -0
- package/node_modules/@commandgarden/app/dist/client/index.html +2 -2
- package/node_modules/@commandgarden/app/dist/server/journal/sources/git.source.d.ts +1 -1
- package/node_modules/@commandgarden/app/dist/server/journal/sources/git.source.js +2 -2
- package/node_modules/@commandgarden/app/dist/server/journal/sources/meetings.source.d.ts +12 -13
- package/node_modules/@commandgarden/app/dist/server/journal/sources/meetings.source.js +70 -17
- package/node_modules/@commandgarden/chrome/dist/service-worker.js +68 -13
- package/node_modules/@commandgarden/chrome/dist/service-worker.js.map +2 -2
- package/node_modules/@commandgarden/daemon/connectors/ado-git-commits.eval.js +76 -119
- package/node_modules/@commandgarden/daemon/connectors/ado-git-commits.yaml +1 -1
- package/node_modules/@commandgarden/daemon/connectors/outlook-my-meetings.eval.js +150 -138
- package/node_modules/@commandgarden/daemon/connectors/outlook-my-meetings.yaml +1 -0
- package/node_modules/@commandgarden/daemon/connectors/teams-room-availability.eval.js +144 -50
- package/node_modules/@commandgarden/daemon/connectors/teams-room-availability.yaml +8 -2
- package/node_modules/@commandgarden/daemon/dist/ws-relay.js +1 -1
- package/package.json +1 -1
- package/node_modules/@commandgarden/app/dist/client/assets/index-DCptfmmK.js +0 -397
- package/node_modules/@commandgarden/app/dist/client/assets/index-qunCIeG9.css +0 -1
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
11
11
|
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" />
|
|
12
12
|
<title>commandGarden</title>
|
|
13
|
-
<script type="module" crossorigin src="/assets/index-
|
|
14
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
13
|
+
<script type="module" crossorigin src="/assets/index-tVkaaa2g.js"></script>
|
|
14
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Dm4TTmUS.css">
|
|
15
15
|
</head>
|
|
16
16
|
<body>
|
|
17
17
|
<div id="root"></div>
|
|
@@ -15,7 +15,7 @@ export declare class GitSource {
|
|
|
15
15
|
private readonly repos;
|
|
16
16
|
private readonly author;
|
|
17
17
|
constructor(daemon: DaemonClient, config: JournalConfig);
|
|
18
|
-
fetch(
|
|
18
|
+
fetch(_weekStart: string, _weekEnd: string): Promise<GitData>;
|
|
19
19
|
/** Fetch a single repo's commits+PRs via the daemon connector. */
|
|
20
20
|
private fetchRepo;
|
|
21
21
|
}
|
|
@@ -17,10 +17,10 @@ export class GitSource {
|
|
|
17
17
|
this.repos = config.azureDevOps.repos;
|
|
18
18
|
this.author = config.author;
|
|
19
19
|
}
|
|
20
|
-
async fetch(
|
|
20
|
+
async fetch(_weekStart, _weekEnd) {
|
|
21
21
|
try {
|
|
22
22
|
// Call the ado/git-commits connector once per configured repo via daemon
|
|
23
|
-
const results = await Promise.all(this.repos.map((r) => this.fetchRepo(r.project, r.repo,
|
|
23
|
+
const results = await Promise.all(this.repos.map((r) => this.fetchRepo(r.project, r.repo, _weekStart, _weekEnd)));
|
|
24
24
|
// Aggregate daily commits across all repos
|
|
25
25
|
const dailyMap = new Map();
|
|
26
26
|
const repoActivity = [];
|
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Meetings data source —
|
|
2
|
+
* Meetings data source — fetches the user's calendar via the
|
|
3
|
+
* outlook/my-meetings connector through the daemon API.
|
|
3
4
|
*
|
|
4
|
-
* The
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* - Graph API: no Graph-scoped MSAL token available in MCAS session storage
|
|
8
|
-
* - Response interception: eval script installs after OWA's initial data fetch
|
|
5
|
+
* The connector uses CDP Scheduling Assistant + getSchedule interception
|
|
6
|
+
* to bypass the MCAS proxy (see docs/ado-git-commits-fix.md for the
|
|
7
|
+
* Runtime.evaluate CSP bypass that also applies here).
|
|
9
8
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* TODO: Revisit post-demo with MCAS-specific auth investigation.
|
|
9
|
+
* Calls the connector once per weekday in the date range, then
|
|
10
|
+
* aggregates into MeetingsData (totalCount, totalHours, daily, entries).
|
|
14
11
|
*/
|
|
15
12
|
import type { DaemonClient } from '@commandgarden/shared';
|
|
16
13
|
import type { MeetingsData } from '../journal.types.js';
|
|
17
14
|
export declare class MeetingsSource {
|
|
18
|
-
private readonly
|
|
19
|
-
constructor(
|
|
20
|
-
fetch(
|
|
15
|
+
private readonly daemon;
|
|
16
|
+
constructor(daemon: DaemonClient);
|
|
17
|
+
fetch(weekStart: string, weekEnd: string): Promise<MeetingsData | null>;
|
|
18
|
+
/** Fetch a single day's meetings via the daemon connector. */
|
|
19
|
+
private fetchDay;
|
|
21
20
|
}
|
|
@@ -1,25 +1,78 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Meetings data source —
|
|
2
|
+
* Meetings data source — fetches the user's calendar via the
|
|
3
|
+
* outlook/my-meetings connector through the daemon API.
|
|
3
4
|
*
|
|
4
|
-
* The
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* - Graph API: no Graph-scoped MSAL token available in MCAS session storage
|
|
8
|
-
* - Response interception: eval script installs after OWA's initial data fetch
|
|
5
|
+
* The connector uses CDP Scheduling Assistant + getSchedule interception
|
|
6
|
+
* to bypass the MCAS proxy (see docs/ado-git-commits-fix.md for the
|
|
7
|
+
* Runtime.evaluate CSP bypass that also applies here).
|
|
9
8
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* TODO: Revisit post-demo with MCAS-specific auth investigation.
|
|
9
|
+
* Calls the connector once per weekday in the date range, then
|
|
10
|
+
* aggregates into MeetingsData (totalCount, totalHours, daily, entries).
|
|
14
11
|
*/
|
|
15
12
|
export class MeetingsSource {
|
|
16
|
-
|
|
17
|
-
constructor(
|
|
18
|
-
this.
|
|
13
|
+
daemon;
|
|
14
|
+
constructor(daemon) {
|
|
15
|
+
this.daemon = daemon;
|
|
16
|
+
}
|
|
17
|
+
async fetch(weekStart, weekEnd) {
|
|
18
|
+
try {
|
|
19
|
+
// Fetch meetings for each weekday in the range.
|
|
20
|
+
// The connector opens the Scheduling Assistant per call, so we
|
|
21
|
+
// batch weekdays sequentially to avoid multiple browser tabs.
|
|
22
|
+
const allEntries = [];
|
|
23
|
+
const cursor = new Date(weekStart);
|
|
24
|
+
const end = new Date(weekEnd);
|
|
25
|
+
while (cursor <= end) {
|
|
26
|
+
const day = cursor.getDay();
|
|
27
|
+
// Only fetch weekdays (Mon–Fri) to avoid unnecessary calls
|
|
28
|
+
if (day >= 1 && day <= 5) {
|
|
29
|
+
const dateStr = cursor.toISOString().slice(0, 10);
|
|
30
|
+
const rows = await this.fetchDay(dateStr);
|
|
31
|
+
for (const r of rows) {
|
|
32
|
+
allEntries.push({
|
|
33
|
+
date: r.date,
|
|
34
|
+
subject: r.subject,
|
|
35
|
+
start: r.start,
|
|
36
|
+
end: r.end,
|
|
37
|
+
durationMin: r.durationMin,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
cursor.setDate(cursor.getDate() + 1);
|
|
42
|
+
}
|
|
43
|
+
if (allEntries.length === 0)
|
|
44
|
+
return null;
|
|
45
|
+
// Aggregate daily stats
|
|
46
|
+
const dailyMap = new Map();
|
|
47
|
+
for (const e of allEntries) {
|
|
48
|
+
const d = dailyMap.get(e.date) ?? { date: e.date, count: 0, hours: 0 };
|
|
49
|
+
d.count += 1;
|
|
50
|
+
d.hours += e.durationMin / 60;
|
|
51
|
+
dailyMap.set(e.date, d);
|
|
52
|
+
}
|
|
53
|
+
const daily = [...dailyMap.values()].sort((a, b) => a.date.localeCompare(b.date));
|
|
54
|
+
const totalCount = allEntries.length;
|
|
55
|
+
const totalMin = allEntries.reduce((s, e) => s + e.durationMin, 0);
|
|
56
|
+
const totalHours = Math.round((totalMin / 60) * 100) / 100;
|
|
57
|
+
const avgDurationMin = Math.round(totalMin / totalCount);
|
|
58
|
+
return { totalCount, totalHours, avgDurationMin, daily, entries: allEntries };
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
console.error('[meetings] fetch error:', e);
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
19
64
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
65
|
+
/** Fetch a single day's meetings via the daemon connector. */
|
|
66
|
+
async fetchDay(date) {
|
|
67
|
+
try {
|
|
68
|
+
const result = await this.daemon.post('/api/run', {
|
|
69
|
+
connector: 'outlook/my-meetings',
|
|
70
|
+
args: { date },
|
|
71
|
+
});
|
|
72
|
+
return result.ok && result.data ? result.data : [];
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
24
77
|
}
|
|
25
78
|
}
|
|
@@ -7140,7 +7140,10 @@ var RealChromeAdapter = class {
|
|
|
7140
7140
|
this.debuggerAttached = true;
|
|
7141
7141
|
await chrome.debugger.sendCommand({ tabId }, "Network.enable");
|
|
7142
7142
|
await chrome.debugger.sendCommand({ tabId }, "Fetch.enable", {
|
|
7143
|
-
patterns: [
|
|
7143
|
+
patterns: [
|
|
7144
|
+
{ urlPattern: "*graphql*", requestStage: "Response" },
|
|
7145
|
+
{ urlPattern: "*_apis/*", requestStage: "Response" }
|
|
7146
|
+
]
|
|
7144
7147
|
}).catch(() => {
|
|
7145
7148
|
});
|
|
7146
7149
|
this.startCapture(tabId);
|
|
@@ -7165,7 +7168,10 @@ var RealChromeAdapter = class {
|
|
|
7165
7168
|
await chrome.debugger.attach({ targetId: swTarget.id }, "1.3");
|
|
7166
7169
|
await chrome.debugger.sendCommand({ targetId: swTarget.id }, "Network.enable");
|
|
7167
7170
|
await chrome.debugger.sendCommand({ targetId: swTarget.id }, "Fetch.enable", {
|
|
7168
|
-
patterns: [
|
|
7171
|
+
patterns: [
|
|
7172
|
+
{ urlPattern: "*graphql*", requestStage: "Response" },
|
|
7173
|
+
{ urlPattern: "*_apis/*", requestStage: "Response" }
|
|
7174
|
+
]
|
|
7169
7175
|
}).catch(() => {
|
|
7170
7176
|
});
|
|
7171
7177
|
const captureTabId = this.tabId;
|
|
@@ -7197,6 +7203,19 @@ var RealChromeAdapter = class {
|
|
|
7197
7203
|
}
|
|
7198
7204
|
}
|
|
7199
7205
|
_swTargetId = null;
|
|
7206
|
+
/** Inject an ADO API response body into the page's globalThis.__cdpCapture array.
|
|
7207
|
+
* Used by ado/git-commits and similar connectors that need CDP-intercepted data. */
|
|
7208
|
+
injectCdpCapture(tabId, body) {
|
|
7209
|
+
chrome.scripting.executeScript({
|
|
7210
|
+
target: { tabId },
|
|
7211
|
+
world: "MAIN",
|
|
7212
|
+
args: [body],
|
|
7213
|
+
func: (data) => {
|
|
7214
|
+
if (!globalThis.__cdpCapture) globalThis.__cdpCapture = [];
|
|
7215
|
+
globalThis.__cdpCapture.push(data);
|
|
7216
|
+
}
|
|
7217
|
+
});
|
|
7218
|
+
}
|
|
7200
7219
|
/** Inject a getSchedule response body into the page's globalThis.__rfb array. */
|
|
7201
7220
|
injectRfb(tabId, body) {
|
|
7202
7221
|
chrome.scripting.executeScript({
|
|
@@ -7221,6 +7240,9 @@ var RealChromeAdapter = class {
|
|
|
7221
7240
|
if (body.includes("getSchedule") && body.includes("availabilityView")) {
|
|
7222
7241
|
this.injectRfb(tabId, body);
|
|
7223
7242
|
}
|
|
7243
|
+
if (body.includes("commitId") || body.includes("pushId") || body.includes("workItems")) {
|
|
7244
|
+
this.injectCdpCapture(tabId, body);
|
|
7245
|
+
}
|
|
7224
7246
|
}).catch(() => {
|
|
7225
7247
|
}).finally(() => {
|
|
7226
7248
|
if (isFetchDomain) {
|
|
@@ -7260,7 +7282,35 @@ var RealChromeAdapter = class {
|
|
|
7260
7282
|
if (!response.ok) throw new Error(response.error ?? "Content script error");
|
|
7261
7283
|
return response.data;
|
|
7262
7284
|
}
|
|
7285
|
+
/**
|
|
7286
|
+
* Run eval.js code via CDP Runtime.evaluate — bypasses CSP because it
|
|
7287
|
+
* executes at the debugger level (like typing in DevTools console).
|
|
7288
|
+
* Required for sites like ADO that use strict-dynamic CSP with nonces,
|
|
7289
|
+
* which blocks new AsyncFunction() / eval() from chrome.scripting.
|
|
7290
|
+
*/
|
|
7291
|
+
async evaluateViaCdp(tabId, code) {
|
|
7292
|
+
const expression = `
|
|
7293
|
+
Promise.race([
|
|
7294
|
+
(async () => { ${code} })(),
|
|
7295
|
+
new Promise((_, rej) => setTimeout(() => rej(new Error('js_evaluate timed out (90s)')), 90000))
|
|
7296
|
+
])
|
|
7297
|
+
`;
|
|
7298
|
+
const result = await chrome.debugger.sendCommand(
|
|
7299
|
+
{ tabId },
|
|
7300
|
+
"Runtime.evaluate",
|
|
7301
|
+
{ expression, awaitPromise: true, returnByValue: true }
|
|
7302
|
+
);
|
|
7303
|
+
const r = result;
|
|
7304
|
+
if (r.exceptionDetails) {
|
|
7305
|
+
const errMsg = r.exceptionDetails.exception?.description || r.exceptionDetails.text;
|
|
7306
|
+
throw new Error(errMsg);
|
|
7307
|
+
}
|
|
7308
|
+
return r.result?.value;
|
|
7309
|
+
}
|
|
7263
7310
|
async evaluateInPage(tabId, code) {
|
|
7311
|
+
if (this.debuggerAttached) {
|
|
7312
|
+
return this.evaluateViaCdp(tabId, code);
|
|
7313
|
+
}
|
|
7264
7314
|
const nonce = "__cg_" + Math.random().toString(36).slice(2);
|
|
7265
7315
|
await chrome.scripting.executeScript({
|
|
7266
7316
|
target: { tabId },
|
|
@@ -7268,19 +7318,24 @@ var RealChromeAdapter = class {
|
|
|
7268
7318
|
args: [code, nonce],
|
|
7269
7319
|
func: (codeStr, key) => {
|
|
7270
7320
|
globalThis[key] = { pending: true };
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
(
|
|
7275
|
-
|
|
7276
|
-
|
|
7277
|
-
|
|
7278
|
-
|
|
7279
|
-
|
|
7280
|
-
|
|
7321
|
+
try {
|
|
7322
|
+
const AsyncFunction = Object.getPrototypeOf(async function() {
|
|
7323
|
+
}).constructor;
|
|
7324
|
+
new AsyncFunction(codeStr)().then(
|
|
7325
|
+
(r) => {
|
|
7326
|
+
globalThis[key] = { ok: true, result: r };
|
|
7327
|
+
},
|
|
7328
|
+
(e) => {
|
|
7329
|
+
globalThis[key] = { ok: false, error: e.message || String(e) };
|
|
7330
|
+
}
|
|
7331
|
+
);
|
|
7332
|
+
} catch (syncErr) {
|
|
7333
|
+
const msg = syncErr instanceof Error ? syncErr.message : String(syncErr);
|
|
7334
|
+
globalThis[key] = { ok: false, error: "[sync] " + msg };
|
|
7335
|
+
}
|
|
7281
7336
|
}
|
|
7282
7337
|
});
|
|
7283
|
-
const deadline = Date.now() +
|
|
7338
|
+
const deadline = Date.now() + 28e4;
|
|
7284
7339
|
while (Date.now() < deadline) {
|
|
7285
7340
|
const [poll] = await chrome.scripting.executeScript({
|
|
7286
7341
|
target: { tabId },
|