@commandgarden/cli 2.5.0 → 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.
Files changed (21) hide show
  1. package/dist/main.js +6 -6
  2. package/node_modules/@commandgarden/app/dist/client/assets/index-Dm4TTmUS.css +1 -0
  3. package/node_modules/@commandgarden/app/dist/client/assets/index-tVkaaa2g.js +421 -0
  4. package/node_modules/@commandgarden/app/dist/client/index.html +2 -2
  5. package/node_modules/@commandgarden/app/dist/server/journal/sources/git.source.d.ts +1 -1
  6. package/node_modules/@commandgarden/app/dist/server/journal/sources/git.source.js +2 -2
  7. package/node_modules/@commandgarden/app/dist/server/journal/sources/meetings.source.d.ts +12 -13
  8. package/node_modules/@commandgarden/app/dist/server/journal/sources/meetings.source.js +70 -17
  9. package/node_modules/@commandgarden/chrome/dist/service-worker.js +68 -13
  10. package/node_modules/@commandgarden/chrome/dist/service-worker.js.map +2 -2
  11. package/node_modules/@commandgarden/daemon/connectors/ado-git-commits.eval.js +76 -119
  12. package/node_modules/@commandgarden/daemon/connectors/ado-git-commits.yaml +1 -1
  13. package/node_modules/@commandgarden/daemon/connectors/outlook-my-meetings.eval.js +150 -138
  14. package/node_modules/@commandgarden/daemon/connectors/outlook-my-meetings.yaml +1 -0
  15. package/node_modules/@commandgarden/daemon/connectors/teams-room-availability.eval.js +144 -50
  16. package/node_modules/@commandgarden/daemon/connectors/teams-room-availability.yaml +8 -2
  17. package/node_modules/@commandgarden/daemon/connectors/teams-rooms-availability.eval.js +2 -0
  18. package/node_modules/@commandgarden/daemon/dist/ws-relay.js +1 -1
  19. package/package.json +1 -1
  20. package/node_modules/@commandgarden/app/dist/client/assets/index-DCptfmmK.js +0 -397
  21. 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-DCptfmmK.js"></script>
14
- <link rel="stylesheet" crossorigin href="/assets/index-qunCIeG9.css">
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(weekStart: string, weekEnd: string): Promise<GitData>;
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(weekStart, weekEnd) {
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, weekStart, weekEnd)));
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 — DISABLED for v1.
2
+ * Meetings data source — fetches the user's calendar via the
3
+ * outlook/my-meetings connector through the daemon API.
3
4
  *
4
- * The Outlook connector is blocked by the corporate MCAS proxy
5
- * (outlook.cloud.microsoft.mcas.ms) which prevents all standard auth patterns:
6
- * - OWA REST API: X-OWA-CANARY cookie is HttpOnly (JS can't read it)
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
- * Returns null immediately the journal renders without meeting data
11
- * (graceful degradation). Git + Jira provide a strong 2-source story.
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 _daemon;
19
- constructor(_daemon: DaemonClient);
20
- fetch(_weekStart: string, _weekEnd: string): Promise<MeetingsData | null>;
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 — DISABLED for v1.
2
+ * Meetings data source — fetches the user's calendar via the
3
+ * outlook/my-meetings connector through the daemon API.
3
4
  *
4
- * The Outlook connector is blocked by the corporate MCAS proxy
5
- * (outlook.cloud.microsoft.mcas.ms) which prevents all standard auth patterns:
6
- * - OWA REST API: X-OWA-CANARY cookie is HttpOnly (JS can't read it)
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
- * Returns null immediately the journal renders without meeting data
11
- * (graceful degradation). Git + Jira provide a strong 2-source story.
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
- _daemon;
17
- constructor(_daemon) {
18
- this._daemon = _daemon;
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
- async fetch(_weekStart, _weekEnd) {
21
- // Disabled for v1 — MCAS proxy blocks all standard auth patterns.
22
- // Returns null so the journal renders without meeting data.
23
- return null;
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: [{ urlPattern: "*graphql*", requestStage: "Response" }]
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: [{ urlPattern: "*graphql*", requestStage: "Response" }]
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
- const AsyncFunction = Object.getPrototypeOf(async function() {
7272
- }).constructor;
7273
- new AsyncFunction(codeStr)().then(
7274
- (r) => {
7275
- globalThis[key] = { ok: true, result: r };
7276
- },
7277
- (e) => {
7278
- globalThis[key] = { ok: false, error: e.message || String(e) };
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() + 9e4;
7338
+ const deadline = Date.now() + 28e4;
7284
7339
  while (Date.now() < deadline) {
7285
7340
  const [poll] = await chrome.scripting.executeScript({
7286
7341
  target: { tabId },