@aaronsb/google-workspace-mcp 2.2.0 → 2.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/build/__tests__/server/handlers/drive.test.js +2 -15
- package/build/__tests__/server/handlers/drive.test.js.map +1 -1
- package/build/__tests__/server/session/context.test.d.ts +1 -0
- package/build/__tests__/server/session/context.test.js +101 -0
- package/build/__tests__/server/session/context.test.js.map +1 -0
- package/build/__tests__/server/session/tracker.test.d.ts +1 -0
- package/build/__tests__/server/session/tracker.test.js +146 -0
- package/build/__tests__/server/session/tracker.test.js.map +1 -0
- package/build/__tests__/services/gmail/mime.test.js +1 -161
- package/build/__tests__/services/gmail/mime.test.js.map +1 -1
- package/build/accounts/oauth.js +17 -8
- package/build/accounts/oauth.js.map +1 -1
- package/build/coverage/analyze.d.ts +13 -0
- package/build/coverage/analyze.js +49 -0
- package/build/coverage/analyze.js.map +1 -0
- package/build/coverage/baseline.d.ts +8 -0
- package/build/coverage/baseline.js +91 -0
- package/build/coverage/baseline.js.map +1 -0
- package/build/coverage/compare.d.ts +6 -0
- package/build/coverage/compare.js +129 -0
- package/build/coverage/compare.js.map +1 -0
- package/build/coverage/discover.d.ts +7 -0
- package/build/coverage/discover.js +168 -0
- package/build/coverage/discover.js.map +1 -0
- package/build/coverage/report.d.ts +6 -0
- package/build/coverage/report.js +93 -0
- package/build/coverage/report.js.map +1 -0
- package/build/coverage/types.d.ts +70 -0
- package/build/coverage/types.js +14 -0
- package/build/coverage/types.js.map +1 -0
- package/build/executor/gws.d.ts +2 -0
- package/build/executor/gws.js +2 -2
- package/build/executor/gws.js.map +1 -1
- package/build/factory/manifest.yaml +183 -6
- package/build/factory/patches.js +2 -0
- package/build/factory/patches.js.map +1 -1
- package/build/server/handler.js +36 -3
- package/build/server/handler.js.map +1 -1
- package/build/server/handlers/calendar.js +8 -4
- package/build/server/handlers/calendar.js.map +1 -1
- package/build/server/handlers/drive.js +0 -16
- package/build/server/handlers/drive.js.map +1 -1
- package/build/server/handlers/workspace.js +63 -0
- package/build/server/handlers/workspace.js.map +1 -1
- package/build/server/scratchpad/adapters/send-email-draft.d.ts +1 -0
- package/build/server/scratchpad/adapters/send-email-draft.js +29 -20
- package/build/server/scratchpad/adapters/send-email-draft.js.map +1 -1
- package/build/server/scratchpad/adapters/send-email.d.ts +2 -1
- package/build/server/scratchpad/adapters/send-email.js +31 -37
- package/build/server/scratchpad/adapters/send-email.js.map +1 -1
- package/build/server/session/context.d.ts +7 -0
- package/build/server/session/context.js +56 -0
- package/build/server/session/context.js.map +1 -0
- package/build/server/session/index.d.ts +9 -0
- package/build/server/session/index.js +14 -0
- package/build/server/session/index.js.map +1 -0
- package/build/server/session/tracker.d.ts +36 -0
- package/build/server/session/tracker.js +135 -0
- package/build/server/session/tracker.js.map +1 -0
- package/build/server/tools.js +4 -4
- package/build/server/tools.js.map +1 -1
- package/build/services/calendar/patch.js +4 -2
- package/build/services/calendar/patch.js.map +1 -1
- package/build/services/docs/patch.d.ts +8 -0
- package/build/services/docs/patch.js +72 -0
- package/build/services/docs/patch.js.map +1 -0
- package/build/services/drive/patch.js +165 -10
- package/build/services/drive/patch.js.map +1 -1
- package/build/services/gmail/mime.d.ts +4 -24
- package/build/services/gmail/mime.js +4 -93
- package/build/services/gmail/mime.js.map +1 -1
- package/build/services/gmail/patch.js +35 -38
- package/build/services/gmail/patch.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Build-time coverage analysis tool (ADR-100).
|
|
4
|
+
*
|
|
5
|
+
* Compares the curated manifest against the gws CLI's actual surface
|
|
6
|
+
* to produce a structured coverage report.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* node build/coverage/analyze.js # print coverage report
|
|
10
|
+
* node build/coverage/analyze.js --update # also update baseline file
|
|
11
|
+
* node build/coverage/analyze.js --json # output as JSON
|
|
12
|
+
*/
|
|
13
|
+
import { loadManifest } from '../factory/generator.js';
|
|
14
|
+
import { discoverSurface } from './discover.js';
|
|
15
|
+
import { compareSurfaces } from './compare.js';
|
|
16
|
+
import { loadBaseline, generateBaseline, writeBaseline } from './baseline.js';
|
|
17
|
+
import { formatTerminalReport, formatJsonReport } from './report.js';
|
|
18
|
+
const args = process.argv.slice(2);
|
|
19
|
+
const doUpdate = args.includes('--update');
|
|
20
|
+
const jsonOutput = args.includes('--json');
|
|
21
|
+
async function main() {
|
|
22
|
+
// Load curated manifest (same parser the server uses)
|
|
23
|
+
const manifest = loadManifest();
|
|
24
|
+
// Load existing baseline (if any)
|
|
25
|
+
const baseline = loadBaseline();
|
|
26
|
+
// Discover the gws CLI surface
|
|
27
|
+
process.stderr.write('[coverage] Discovering gws CLI surface...\n');
|
|
28
|
+
const discovered = discoverSurface();
|
|
29
|
+
// Compare
|
|
30
|
+
const report = compareSurfaces(manifest, discovered, baseline);
|
|
31
|
+
// Output
|
|
32
|
+
if (jsonOutput) {
|
|
33
|
+
process.stdout.write(formatJsonReport(report) + '\n');
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
process.stdout.write(formatTerminalReport(report));
|
|
37
|
+
}
|
|
38
|
+
// Update baseline if requested
|
|
39
|
+
if (doUpdate) {
|
|
40
|
+
const newBaseline = generateBaseline(report, discovered, baseline);
|
|
41
|
+
const path = writeBaseline(newBaseline);
|
|
42
|
+
process.stderr.write(`[coverage] Baseline updated: ${path}\n`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
main().catch((err) => {
|
|
46
|
+
process.stderr.write(`[coverage] Error: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
});
|
|
49
|
+
//# sourceMappingURL=analyze.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/coverage/analyze.ts"],"names":[],"mappings":";AACA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAErE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;AAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAE3C,KAAK,UAAU,IAAI;IACjB,sDAAsD;IACtD,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;IAEhC,kCAAkC;IAClC,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;IAEhC,+BAA+B;IAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACpE,MAAM,UAAU,GAAG,eAAe,EAAE,CAAC;IAErC,UAAU;IACV,MAAM,MAAM,GAAG,eAAe,CAAC,QAAQ,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;IAE/D,SAAS;IACT,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;IACxD,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC;IACrD,CAAC;IAED,+BAA+B;IAC/B,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,WAAW,GAAG,gBAAgB,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;QACnE,MAAM,IAAI,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;QACxC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,IAAI,IAAI,CAAC,CAAC;IACjE,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qBAAqB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Baseline file management for coverage tracking.
|
|
3
|
+
*/
|
|
4
|
+
import type { CoverageBaseline, CoverageReport, DiscoveredSurface } from './types.js';
|
|
5
|
+
export declare function loadBaseline(filePath?: string): CoverageBaseline | null;
|
|
6
|
+
/** Generate a new baseline from a coverage report + discovered surface. */
|
|
7
|
+
export declare function generateBaseline(report: CoverageReport, discovered: DiscoveredSurface, existing?: CoverageBaseline | null): CoverageBaseline;
|
|
8
|
+
export declare function writeBaseline(baseline: CoverageBaseline, filePath?: string): string;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Baseline file management for coverage tracking.
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from 'node:fs';
|
|
5
|
+
import * as path from 'node:path';
|
|
6
|
+
const DEFAULT_PATH = 'coverage-baseline.json';
|
|
7
|
+
function resolvePath(filePath) {
|
|
8
|
+
const p = filePath || DEFAULT_PATH;
|
|
9
|
+
return path.isAbsolute(p) ? p : path.join(process.cwd(), p);
|
|
10
|
+
}
|
|
11
|
+
export function loadBaseline(filePath) {
|
|
12
|
+
const resolved = resolvePath(filePath);
|
|
13
|
+
try {
|
|
14
|
+
const raw = fs.readFileSync(resolved, 'utf-8');
|
|
15
|
+
return JSON.parse(raw);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** Build the set of manifest-covered resource/helper paths. */
|
|
22
|
+
function getCoveredPaths(report) {
|
|
23
|
+
const covered = new Set();
|
|
24
|
+
for (const svc of report.services) {
|
|
25
|
+
// Ops with param gaps are covered
|
|
26
|
+
for (const opPath of Object.keys(svc.paramGaps)) {
|
|
27
|
+
covered.add(`${svc.service}:${opPath}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return covered;
|
|
31
|
+
}
|
|
32
|
+
/** Generate a new baseline from a coverage report + discovered surface. */
|
|
33
|
+
export function generateBaseline(report, discovered, existing) {
|
|
34
|
+
const services = {};
|
|
35
|
+
// Build a lookup of covered paths from the report's param gaps
|
|
36
|
+
// (ops with param gaps are definitely covered)
|
|
37
|
+
const paramGapPaths = getCoveredPaths(report);
|
|
38
|
+
for (const svc of report.services) {
|
|
39
|
+
const disc = discovered.services[svc.service];
|
|
40
|
+
if (!disc)
|
|
41
|
+
continue;
|
|
42
|
+
const existingOps = existing?.services[svc.service]?.operations || {};
|
|
43
|
+
const operations = {};
|
|
44
|
+
// Enumerate all discovered operations
|
|
45
|
+
const allPaths = new Set([
|
|
46
|
+
...Object.keys(disc.operations),
|
|
47
|
+
...Object.keys(disc.helpers),
|
|
48
|
+
]);
|
|
49
|
+
for (const opPath of allPaths) {
|
|
50
|
+
// Check if excluded in existing baseline — preserve
|
|
51
|
+
if (existingOps[opPath]?.status === 'excluded') {
|
|
52
|
+
operations[opPath] = existingOps[opPath];
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
// Check if covered (has param gaps recorded)
|
|
56
|
+
const key = `${svc.service}:${opPath}`;
|
|
57
|
+
if (paramGapPaths.has(key)) {
|
|
58
|
+
const gaps = svc.paramGaps[opPath] || [];
|
|
59
|
+
operations[opPath] = {
|
|
60
|
+
status: 'covered',
|
|
61
|
+
params: gaps.length > 0
|
|
62
|
+
? Object.fromEntries(gaps.map(g => [g.paramName, g.inManifest ? 'covered' : 'gap']))
|
|
63
|
+
: undefined,
|
|
64
|
+
};
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
// Check if it's covered but without param gaps — need to check the report counts
|
|
68
|
+
// We can infer from whether the op was NOT in newOps and NOT excluded
|
|
69
|
+
const isNew = svc.newOps.includes(opPath);
|
|
70
|
+
const wasCovered = existingOps[opPath]?.status === 'covered';
|
|
71
|
+
if (wasCovered && !isNew) {
|
|
72
|
+
operations[opPath] = { status: 'covered' };
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
operations[opPath] = { status: 'gap' };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
services[svc.service] = { operations };
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
gwsVersion: report.gwsVersion,
|
|
82
|
+
generatedAt: report.timestamp,
|
|
83
|
+
services,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
export function writeBaseline(baseline, filePath) {
|
|
87
|
+
const resolved = resolvePath(filePath);
|
|
88
|
+
fs.writeFileSync(resolved, JSON.stringify(baseline, null, 2) + '\n');
|
|
89
|
+
return resolved;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=baseline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baseline.js","sourceRoot":"","sources":["../../src/coverage/baseline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compare curated manifest against discovered gws CLI surface.
|
|
3
|
+
*/
|
|
4
|
+
import type { Manifest } from '../factory/types.js';
|
|
5
|
+
import type { DiscoveredSurface, CoverageBaseline, CoverageReport } from './types.js';
|
|
6
|
+
export declare function compareSurfaces(manifest: Manifest, discovered: DiscoveredSurface, baseline?: CoverageBaseline | null): CoverageReport;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compare curated manifest against discovered gws CLI surface.
|
|
3
|
+
*/
|
|
4
|
+
import { ELIGIBLE_SERVICES, SKIP_PARAMS } from './types.js';
|
|
5
|
+
/** Build a set of gws resource paths and helper names covered by the manifest. */
|
|
6
|
+
function buildCoveredPaths(manifest) {
|
|
7
|
+
const covered = new Map();
|
|
8
|
+
for (const [serviceName, serviceDef] of Object.entries(manifest.services)) {
|
|
9
|
+
for (const [opName, opDef] of Object.entries(serviceDef.operations)) {
|
|
10
|
+
const path = opDef.resource || opDef.helper;
|
|
11
|
+
if (!path)
|
|
12
|
+
continue;
|
|
13
|
+
const paramNames = new Set();
|
|
14
|
+
if (opDef.params) {
|
|
15
|
+
for (const [name, paramDef] of Object.entries(opDef.params)) {
|
|
16
|
+
// Use maps_to if declared, otherwise the param name itself
|
|
17
|
+
paramNames.add(paramDef.maps_to || name);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
covered.set(path, {
|
|
21
|
+
service: serviceDef.gws_service,
|
|
22
|
+
opName,
|
|
23
|
+
params: paramNames,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return covered;
|
|
28
|
+
}
|
|
29
|
+
/** Compare params for a covered operation. */
|
|
30
|
+
function compareParams(manifestParams, gwsParams) {
|
|
31
|
+
const gaps = [];
|
|
32
|
+
for (const [name, param] of Object.entries(gwsParams)) {
|
|
33
|
+
if (SKIP_PARAMS.has(name))
|
|
34
|
+
continue;
|
|
35
|
+
if (param.deprecated)
|
|
36
|
+
continue;
|
|
37
|
+
if (!manifestParams.has(name)) {
|
|
38
|
+
gaps.push({
|
|
39
|
+
paramName: name,
|
|
40
|
+
inGws: true,
|
|
41
|
+
inManifest: false,
|
|
42
|
+
details: `${param.type}${param.required ? ', required' : ''} — ${param.description.slice(0, 80)}`,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return gaps;
|
|
47
|
+
}
|
|
48
|
+
export function compareSurfaces(manifest, discovered, baseline) {
|
|
49
|
+
const coveredPaths = buildCoveredPaths(manifest);
|
|
50
|
+
const serviceCoverages = [];
|
|
51
|
+
let totalOps = 0;
|
|
52
|
+
let totalCovered = 0;
|
|
53
|
+
for (const service of ELIGIBLE_SERVICES) {
|
|
54
|
+
const disc = discovered.services[service];
|
|
55
|
+
if (!disc) {
|
|
56
|
+
// Service exists in eligible list but gws doesn't expose it
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const baselineOps = baseline?.services[service]?.operations || {};
|
|
60
|
+
const allOps = new Set();
|
|
61
|
+
// Add resource-based operations
|
|
62
|
+
for (const path of Object.keys(disc.operations)) {
|
|
63
|
+
allOps.add(path);
|
|
64
|
+
}
|
|
65
|
+
// Add helpers
|
|
66
|
+
for (const name of Object.keys(disc.helpers)) {
|
|
67
|
+
allOps.add(name);
|
|
68
|
+
}
|
|
69
|
+
let covered = 0;
|
|
70
|
+
let excluded = 0;
|
|
71
|
+
let gap = 0;
|
|
72
|
+
const newOps = [];
|
|
73
|
+
const removedOps = [];
|
|
74
|
+
const paramGaps = {};
|
|
75
|
+
for (const opPath of allOps) {
|
|
76
|
+
const isCovered = coveredPaths.has(opPath);
|
|
77
|
+
const baselineEntry = baselineOps[opPath];
|
|
78
|
+
const wasInBaseline = !!baselineEntry;
|
|
79
|
+
if (isCovered) {
|
|
80
|
+
covered++;
|
|
81
|
+
// Check param gaps for resource-based operations
|
|
82
|
+
const discOp = disc.operations[opPath];
|
|
83
|
+
const manifestEntry = coveredPaths.get(opPath);
|
|
84
|
+
if (discOp && manifestEntry) {
|
|
85
|
+
const gaps = compareParams(manifestEntry.params, discOp.params);
|
|
86
|
+
if (gaps.length > 0) {
|
|
87
|
+
paramGaps[opPath] = gaps;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else if (baselineEntry?.status === 'excluded') {
|
|
92
|
+
excluded++;
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
gap++;
|
|
96
|
+
if (!wasInBaseline) {
|
|
97
|
+
newOps.push(opPath);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Check for removed operations (in baseline but gone from gws)
|
|
102
|
+
for (const opPath of Object.keys(baselineOps)) {
|
|
103
|
+
if (!allOps.has(opPath)) {
|
|
104
|
+
removedOps.push(opPath);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
totalOps += allOps.size;
|
|
108
|
+
totalCovered += covered;
|
|
109
|
+
serviceCoverages.push({
|
|
110
|
+
service,
|
|
111
|
+
totalOps: allOps.size,
|
|
112
|
+
coveredOps: covered,
|
|
113
|
+
excludedOps: excluded,
|
|
114
|
+
gapOps: gap,
|
|
115
|
+
newOps,
|
|
116
|
+
removedOps,
|
|
117
|
+
paramGaps,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
gwsVersion: discovered.gwsVersion,
|
|
122
|
+
timestamp: new Date().toISOString(),
|
|
123
|
+
totalOps: totalOps,
|
|
124
|
+
coveredOps: totalCovered,
|
|
125
|
+
coveragePercent: totalOps > 0 ? Math.round((totalCovered / totalOps) * 100) : 0,
|
|
126
|
+
services: serviceCoverages,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=compare.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare.js","sourceRoot":"","sources":["../../src/coverage/compare.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gws CLI surface discovery — enumerates services, resources, methods,
|
|
3
|
+
* helpers, and parameter schemas by invoking the gws binary.
|
|
4
|
+
*/
|
|
5
|
+
import { type DiscoveredSurface } from './types.js';
|
|
6
|
+
/** Discover the full gws CLI surface for all eligible services. */
|
|
7
|
+
export declare function discoverSurface(): DiscoveredSurface;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gws CLI surface discovery — enumerates services, resources, methods,
|
|
3
|
+
* helpers, and parameter schemas by invoking the gws binary.
|
|
4
|
+
*/
|
|
5
|
+
import { execFileSync } from 'node:child_process';
|
|
6
|
+
import { resolveGwsBinary } from '../executor/gws.js';
|
|
7
|
+
import { ELIGIBLE_SERVICES, SKIP_PARAMS, } from './types.js';
|
|
8
|
+
const TIMEOUT = 10_000;
|
|
9
|
+
let cachedBinary;
|
|
10
|
+
function getBinary() {
|
|
11
|
+
if (!cachedBinary)
|
|
12
|
+
cachedBinary = resolveGwsBinary();
|
|
13
|
+
return cachedBinary;
|
|
14
|
+
}
|
|
15
|
+
function gws(args) {
|
|
16
|
+
return execFileSync(getBinary(), args, {
|
|
17
|
+
encoding: 'utf8',
|
|
18
|
+
timeout: TIMEOUT,
|
|
19
|
+
env: { ...process.env },
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function gwsSafe(args) {
|
|
23
|
+
try {
|
|
24
|
+
return execFileSync(getBinary(), args, {
|
|
25
|
+
encoding: 'utf8',
|
|
26
|
+
timeout: TIMEOUT,
|
|
27
|
+
env: { ...process.env },
|
|
28
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** Parse service --help to find resources and helpers. */
|
|
36
|
+
function parseServiceHelp(output) {
|
|
37
|
+
const resources = [];
|
|
38
|
+
const helpers = [];
|
|
39
|
+
for (const line of output.split('\n')) {
|
|
40
|
+
const trimmed = line.trimStart();
|
|
41
|
+
// Helpers: lines starting with +
|
|
42
|
+
const helperMatch = trimmed.match(/^(\+\w+)\s+(?:\[Helper\]\s*)?(.*)$/);
|
|
43
|
+
if (helperMatch) {
|
|
44
|
+
helpers.push({ name: helperMatch[1], description: helperMatch[2].trim() });
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
// Resources: "word Operations on the '...' resource"
|
|
48
|
+
const resourceMatch = trimmed.match(/^(\w+)\s+Operations on the/);
|
|
49
|
+
if (resourceMatch && resourceMatch[1] !== 'help') {
|
|
50
|
+
resources.push(resourceMatch[1]);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return { resources, helpers };
|
|
54
|
+
}
|
|
55
|
+
/** Parse resource --help to find methods and sub-resources. */
|
|
56
|
+
function parseResourceHelp(output) {
|
|
57
|
+
const methods = [];
|
|
58
|
+
const subResources = [];
|
|
59
|
+
for (const line of output.split('\n')) {
|
|
60
|
+
const trimmed = line.trimStart();
|
|
61
|
+
if (!trimmed || trimmed.startsWith('Usage:') || trimmed.startsWith('FLAGS:'))
|
|
62
|
+
continue;
|
|
63
|
+
const resourceMatch = trimmed.match(/^(\w+)\s+Operations on the/);
|
|
64
|
+
if (resourceMatch && resourceMatch[1] !== 'help') {
|
|
65
|
+
subResources.push(resourceMatch[1]);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
// Methods: "word Description text" (not "help", not "Operations on")
|
|
69
|
+
const methodMatch = trimmed.match(/^(\w+)\s+\S/);
|
|
70
|
+
if (methodMatch && methodMatch[1] !== 'help' && !trimmed.includes('Operations on')) {
|
|
71
|
+
methods.push(methodMatch[1]);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return { methods, subResources };
|
|
75
|
+
}
|
|
76
|
+
/** Parse gws schema JSON output into DiscoveredParam records. */
|
|
77
|
+
function parseSchemaParams(json) {
|
|
78
|
+
const params = {};
|
|
79
|
+
try {
|
|
80
|
+
const schema = JSON.parse(json);
|
|
81
|
+
const rawParams = schema.parameters || {};
|
|
82
|
+
for (const [name, def] of Object.entries(rawParams)) {
|
|
83
|
+
if (SKIP_PARAMS.has(name))
|
|
84
|
+
continue;
|
|
85
|
+
const p = def;
|
|
86
|
+
params[name] = {
|
|
87
|
+
type: String(p.type === 'integer' ? 'number' : (p.type || 'string')),
|
|
88
|
+
description: String(p.description || '').replace(/\n/g, ' ').slice(0, 200),
|
|
89
|
+
required: Boolean(p.required),
|
|
90
|
+
...(p.default !== undefined ? { default: p.default } : {}),
|
|
91
|
+
...(p.enum ? { enum: p.enum } : {}),
|
|
92
|
+
...(p.deprecated ? { deprecated: true } : {}),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// Schema parse failed — return empty params
|
|
98
|
+
}
|
|
99
|
+
return params;
|
|
100
|
+
}
|
|
101
|
+
/** Recursively discover methods under a resource path. */
|
|
102
|
+
function discoverResource(service, parentPath, parts) {
|
|
103
|
+
const operations = {};
|
|
104
|
+
const helpOutput = gwsSafe([service, ...parts, '--help']);
|
|
105
|
+
if (!helpOutput)
|
|
106
|
+
return operations;
|
|
107
|
+
const { methods, subResources } = parseResourceHelp(helpOutput);
|
|
108
|
+
for (const method of methods) {
|
|
109
|
+
const resourcePath = `${parentPath}.${method}`;
|
|
110
|
+
// gws schema uses flat resource names (e.g. drive.replies.list),
|
|
111
|
+
// not nested CLI paths (e.g. drive.comments.replies.list).
|
|
112
|
+
// Try the full path first, fall back to leaf resource + method.
|
|
113
|
+
const leafResource = parts[parts.length - 1];
|
|
114
|
+
const schemaOutput = gwsSafe(['schema', `${service}.${parentPath}.${method}`])
|
|
115
|
+
|| (parts.length > 1 ? gwsSafe(['schema', `${service}.${leafResource}.${method}`]) : null);
|
|
116
|
+
let params = {};
|
|
117
|
+
let description = '';
|
|
118
|
+
let httpMethod;
|
|
119
|
+
if (schemaOutput) {
|
|
120
|
+
params = parseSchemaParams(schemaOutput);
|
|
121
|
+
try {
|
|
122
|
+
const schema = JSON.parse(schemaOutput);
|
|
123
|
+
description = String(schema.description || '').replace(/\n/g, ' ').slice(0, 200);
|
|
124
|
+
httpMethod = schema.httpMethod;
|
|
125
|
+
}
|
|
126
|
+
catch { /* ignore */ }
|
|
127
|
+
}
|
|
128
|
+
operations[resourcePath] = { resourcePath, description, httpMethod, params };
|
|
129
|
+
}
|
|
130
|
+
for (const sub of subResources) {
|
|
131
|
+
const subOps = discoverResource(service, `${parentPath}.${sub}`, [...parts, sub]);
|
|
132
|
+
Object.assign(operations, subOps);
|
|
133
|
+
}
|
|
134
|
+
return operations;
|
|
135
|
+
}
|
|
136
|
+
/** Discover the full surface of a single gws service. */
|
|
137
|
+
function discoverService(service) {
|
|
138
|
+
const helpOutput = gwsSafe([service, '--help']);
|
|
139
|
+
if (!helpOutput)
|
|
140
|
+
return { operations: {}, helpers: {} };
|
|
141
|
+
const { resources, helpers } = parseServiceHelp(helpOutput);
|
|
142
|
+
const helperMap = {};
|
|
143
|
+
for (const h of helpers) {
|
|
144
|
+
helperMap[h.name] = h;
|
|
145
|
+
}
|
|
146
|
+
let operations = {};
|
|
147
|
+
for (const resource of resources) {
|
|
148
|
+
const resourceOps = discoverResource(service, resource, [resource]);
|
|
149
|
+
operations = { ...operations, ...resourceOps };
|
|
150
|
+
}
|
|
151
|
+
return { operations, helpers: helperMap };
|
|
152
|
+
}
|
|
153
|
+
/** Discover the full gws CLI surface for all eligible services. */
|
|
154
|
+
export function discoverSurface() {
|
|
155
|
+
// Get gws version
|
|
156
|
+
let gwsVersion = 'unknown';
|
|
157
|
+
try {
|
|
158
|
+
gwsVersion = gws(['--version']).trim().split('\n')[0];
|
|
159
|
+
}
|
|
160
|
+
catch { /* ignore */ }
|
|
161
|
+
const services = {};
|
|
162
|
+
for (const service of ELIGIBLE_SERVICES) {
|
|
163
|
+
process.stderr.write(`[coverage] discovering ${service}...\n`);
|
|
164
|
+
services[service] = discoverService(service);
|
|
165
|
+
}
|
|
166
|
+
return { gwsVersion, services };
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=discover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover.js","sourceRoot":"","sources":["../../src/coverage/discover.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format coverage reports for terminal and JSON output.
|
|
3
|
+
*/
|
|
4
|
+
import type { CoverageReport } from './types.js';
|
|
5
|
+
export declare function formatTerminalReport(report: CoverageReport): string;
|
|
6
|
+
export declare function formatJsonReport(report: CoverageReport): string;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format coverage reports for terminal and JSON output.
|
|
3
|
+
*/
|
|
4
|
+
const BOLD = '\x1b[1m';
|
|
5
|
+
const DIM = '\x1b[2m';
|
|
6
|
+
const GREEN = '\x1b[32m';
|
|
7
|
+
const YELLOW = '\x1b[33m';
|
|
8
|
+
const RED = '\x1b[31m';
|
|
9
|
+
const CYAN = '\x1b[36m';
|
|
10
|
+
const RESET = '\x1b[0m';
|
|
11
|
+
function bar(covered, total, width = 20) {
|
|
12
|
+
if (total === 0)
|
|
13
|
+
return DIM + '░'.repeat(width) + RESET;
|
|
14
|
+
const filled = Math.round((covered / total) * width);
|
|
15
|
+
const color = (covered / total) >= 0.5 ? GREEN : (covered / total) >= 0.25 ? YELLOW : RED;
|
|
16
|
+
return color + '█'.repeat(filled) + RESET + DIM + '░'.repeat(width - filled) + RESET;
|
|
17
|
+
}
|
|
18
|
+
function pct(n, total) {
|
|
19
|
+
if (total === 0)
|
|
20
|
+
return ' -';
|
|
21
|
+
return `${Math.round((n / total) * 100).toString().padStart(3)}%`;
|
|
22
|
+
}
|
|
23
|
+
export function formatTerminalReport(report) {
|
|
24
|
+
const lines = [];
|
|
25
|
+
lines.push('');
|
|
26
|
+
lines.push(`${BOLD}gws CLI Coverage Analysis${RESET}`);
|
|
27
|
+
lines.push(`${DIM}gws version: ${report.gwsVersion}${RESET}`);
|
|
28
|
+
lines.push(`${DIM}timestamp: ${report.timestamp}${RESET}`);
|
|
29
|
+
lines.push('');
|
|
30
|
+
// Summary
|
|
31
|
+
lines.push(`${BOLD}Coverage: ${report.coveredOps}/${report.totalOps} operations (${report.coveragePercent}%)${RESET}`);
|
|
32
|
+
lines.push('');
|
|
33
|
+
// Per-service table
|
|
34
|
+
const header = ` ${'Service'.padEnd(14)} ${'Covered'.padStart(8)} ${' '.repeat(20)} ${'Pct'.padStart(4)} ${'Gaps'.padStart(5)} ${'Excl'.padStart(5)}`;
|
|
35
|
+
lines.push(`${DIM}${header}${RESET}`);
|
|
36
|
+
lines.push(`${DIM} ${'─'.repeat(14)} ${'─'.repeat(8)} ${'─'.repeat(20)} ${'─'.repeat(4)} ${'─'.repeat(5)} ${'─'.repeat(5)}${RESET}`);
|
|
37
|
+
for (const svc of report.services) {
|
|
38
|
+
if (svc.totalOps === 0)
|
|
39
|
+
continue;
|
|
40
|
+
const svcName = svc.service.padEnd(14);
|
|
41
|
+
const ratio = `${svc.coveredOps}/${svc.totalOps}`.padStart(8);
|
|
42
|
+
const barStr = bar(svc.coveredOps, svc.totalOps);
|
|
43
|
+
const pctStr = pct(svc.coveredOps, svc.totalOps);
|
|
44
|
+
const gapStr = (svc.gapOps > 0 ? `${svc.gapOps}` : '-').padStart(5);
|
|
45
|
+
const exclStr = (svc.excludedOps > 0 ? `${svc.excludedOps}` : '-').padStart(5);
|
|
46
|
+
lines.push(` ${svcName} ${ratio} ${barStr} ${pctStr} ${gapStr} ${exclStr}`);
|
|
47
|
+
}
|
|
48
|
+
// Uncovered services
|
|
49
|
+
const uncoveredServices = report.services.filter(s => s.coveredOps === 0 && s.totalOps > 0);
|
|
50
|
+
if (uncoveredServices.length > 0) {
|
|
51
|
+
lines.push('');
|
|
52
|
+
lines.push(`${BOLD}Uncovered services:${RESET}`);
|
|
53
|
+
for (const svc of uncoveredServices) {
|
|
54
|
+
lines.push(` ${YELLOW}${svc.service}${RESET} — ${svc.totalOps} operations available`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// New operations since baseline
|
|
58
|
+
const newOps = report.services.flatMap(s => s.newOps.map(op => ({ service: s.service, op })));
|
|
59
|
+
if (newOps.length > 0) {
|
|
60
|
+
lines.push('');
|
|
61
|
+
lines.push(`${BOLD}New since baseline:${RESET}`);
|
|
62
|
+
for (const { service, op } of newOps) {
|
|
63
|
+
lines.push(` ${GREEN}+${RESET} ${CYAN}${service}${RESET} ${op}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Removed operations
|
|
67
|
+
const removedOps = report.services.flatMap(s => s.removedOps.map(op => ({ service: s.service, op })));
|
|
68
|
+
if (removedOps.length > 0) {
|
|
69
|
+
lines.push('');
|
|
70
|
+
lines.push(`${BOLD}Removed from gws:${RESET}`);
|
|
71
|
+
for (const { service, op } of removedOps) {
|
|
72
|
+
lines.push(` ${RED}-${RESET} ${CYAN}${service}${RESET} ${op}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Parameter gaps
|
|
76
|
+
const allParamGaps = report.services.flatMap(s => Object.entries(s.paramGaps).map(([op, gaps]) => ({ service: s.service, op, gaps })));
|
|
77
|
+
if (allParamGaps.length > 0) {
|
|
78
|
+
lines.push('');
|
|
79
|
+
lines.push(`${BOLD}Parameter gaps in covered operations:${RESET}`);
|
|
80
|
+
for (const { service, op, gaps } of allParamGaps) {
|
|
81
|
+
lines.push(` ${CYAN}${service}${RESET} ${op}:`);
|
|
82
|
+
for (const gap of gaps) {
|
|
83
|
+
lines.push(` ${YELLOW}+${RESET} ${gap.paramName} ${DIM}(${gap.details || 'missing'})${RESET}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
lines.push('');
|
|
88
|
+
return lines.join('\n');
|
|
89
|
+
}
|
|
90
|
+
export function formatJsonReport(report) {
|
|
91
|
+
return JSON.stringify(report, null, 2);
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/coverage/report.ts"],"names":[],"mappings":"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"}
|