hackmyagent 0.10.1 → 0.11.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/README.md +108 -272
- package/dist/arp/index.d.ts +5 -1
- package/dist/arp/index.d.ts.map +1 -1
- package/dist/arp/index.js +38 -1
- package/dist/arp/index.js.map +1 -1
- package/dist/arp/monitors/skill-capability-monitor.d.ts +119 -0
- package/dist/arp/monitors/skill-capability-monitor.d.ts.map +1 -0
- package/dist/arp/monitors/skill-capability-monitor.js +258 -0
- package/dist/arp/monitors/skill-capability-monitor.js.map +1 -0
- package/dist/arp/telemetry/forwarder.d.ts +62 -0
- package/dist/arp/telemetry/forwarder.d.ts.map +1 -0
- package/dist/arp/telemetry/forwarder.js +106 -0
- package/dist/arp/telemetry/forwarder.js.map +1 -0
- package/dist/arp/telemetry/gtin.d.ts +87 -0
- package/dist/arp/telemetry/gtin.d.ts.map +1 -0
- package/dist/arp/telemetry/gtin.js +239 -0
- package/dist/arp/telemetry/gtin.js.map +1 -0
- package/dist/arp/telemetry/index.d.ts +6 -0
- package/dist/arp/telemetry/index.d.ts.map +1 -0
- package/dist/arp/telemetry/index.js +17 -0
- package/dist/arp/telemetry/index.js.map +1 -0
- package/dist/arp/types.d.ts +10 -0
- package/dist/arp/types.d.ts.map +1 -1
- package/dist/attack/index.d.ts +1 -1
- package/dist/attack/index.d.ts.map +1 -1
- package/dist/attack/index.js +5 -1
- package/dist/attack/index.js.map +1 -1
- package/dist/attack/payloads/context-window.d.ts +7 -0
- package/dist/attack/payloads/context-window.d.ts.map +1 -0
- package/dist/attack/payloads/context-window.js +110 -0
- package/dist/attack/payloads/context-window.js.map +1 -0
- package/dist/attack/payloads/index.d.ts +5 -1
- package/dist/attack/payloads/index.d.ts.map +1 -1
- package/dist/attack/payloads/index.js +17 -1
- package/dist/attack/payloads/index.js.map +1 -1
- package/dist/attack/payloads/memory-weaponization.d.ts +7 -0
- package/dist/attack/payloads/memory-weaponization.d.ts.map +1 -0
- package/dist/attack/payloads/memory-weaponization.js +110 -0
- package/dist/attack/payloads/memory-weaponization.js.map +1 -0
- package/dist/attack/payloads/supply-chain.d.ts +7 -0
- package/dist/attack/payloads/supply-chain.d.ts.map +1 -0
- package/dist/attack/payloads/supply-chain.js +110 -0
- package/dist/attack/payloads/supply-chain.js.map +1 -0
- package/dist/attack/payloads/tool-shadow.d.ts +8 -0
- package/dist/attack/payloads/tool-shadow.d.ts.map +1 -0
- package/dist/attack/payloads/tool-shadow.js +209 -0
- package/dist/attack/payloads/tool-shadow.js.map +1 -0
- package/dist/attack/scanner.d.ts.map +1 -1
- package/dist/attack/scanner.js +4 -0
- package/dist/attack/scanner.js.map +1 -1
- package/dist/attack/types.d.ts +1 -1
- package/dist/attack/types.d.ts.map +1 -1
- package/dist/attack/types.js +20 -0
- package/dist/attack/types.js.map +1 -1
- package/dist/checker/index.d.ts +2 -0
- package/dist/checker/index.d.ts.map +1 -1
- package/dist/checker/index.js +8 -1
- package/dist/checker/index.js.map +1 -1
- package/dist/checker/skill-dependency-graph.d.ts +55 -0
- package/dist/checker/skill-dependency-graph.d.ts.map +1 -0
- package/dist/checker/skill-dependency-graph.js +288 -0
- package/dist/checker/skill-dependency-graph.js.map +1 -0
- package/dist/cli.js +481 -66
- package/dist/cli.js.map +1 -1
- package/dist/hardening/index.d.ts +5 -0
- package/dist/hardening/index.d.ts.map +1 -1
- package/dist/hardening/index.js +11 -1
- package/dist/hardening/index.js.map +1 -1
- package/dist/hardening/scanner.d.ts +40 -0
- package/dist/hardening/scanner.d.ts.map +1 -1
- package/dist/hardening/scanner.js +988 -11
- package/dist/hardening/scanner.js.map +1 -1
- package/dist/hardening/security-check.d.ts +2 -0
- package/dist/hardening/security-check.d.ts.map +1 -1
- package/dist/hardening/skill-capability-validator.d.ts +31 -0
- package/dist/hardening/skill-capability-validator.d.ts.map +1 -0
- package/dist/hardening/skill-capability-validator.js +237 -0
- package/dist/hardening/skill-capability-validator.js.map +1 -0
- package/dist/hardening/skill-context.d.ts +22 -0
- package/dist/hardening/skill-context.d.ts.map +1 -0
- package/dist/hardening/skill-context.js +127 -0
- package/dist/hardening/skill-context.js.map +1 -0
- package/dist/hardening/taxonomy.d.ts +17 -0
- package/dist/hardening/taxonomy.d.ts.map +1 -0
- package/dist/hardening/taxonomy.js +152 -0
- package/dist/hardening/taxonomy.js.map +1 -0
- package/dist/index.d.ts +12 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +36 -3
- package/dist/index.js.map +1 -1
- package/dist/plugins/credvault.js +2 -2
- package/dist/plugins/credvault.js.map +1 -1
- package/dist/plugins/secretless.d.ts +15 -0
- package/dist/plugins/secretless.d.ts.map +1 -0
- package/dist/plugins/secretless.js +199 -0
- package/dist/plugins/secretless.js.map +1 -0
- package/dist/plugins/signcrypt.js +2 -2
- package/dist/plugins/signcrypt.js.map +1 -1
- package/dist/plugins/skillguard.js +2 -2
- package/dist/plugins/skillguard.js.map +1 -1
- package/dist/resolve-mcp.d.ts +21 -0
- package/dist/resolve-mcp.d.ts.map +1 -0
- package/dist/resolve-mcp.js +42 -0
- package/dist/resolve-mcp.js.map +1 -0
- package/dist/scanner/external-scanner.js +5 -5
- package/dist/scanner/external-scanner.js.map +1 -1
- package/dist/telemetry/contribute.d.ts +60 -0
- package/dist/telemetry/contribute.d.ts.map +1 -0
- package/dist/telemetry/contribute.js +169 -0
- package/dist/telemetry/contribute.js.map +1 -0
- package/dist/telemetry/index.d.ts +6 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +18 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/opt-in.d.ts +46 -0
- package/dist/telemetry/opt-in.d.ts.map +1 -0
- package/dist/telemetry/opt-in.js +220 -0
- package/dist/telemetry/opt-in.js.map +1 -0
- package/package.json +9 -3
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MCP package name shorthand resolution.
|
|
4
|
+
*
|
|
5
|
+
* Converts short forms like "server-filesystem" or "mcp-server-fetch"
|
|
6
|
+
* into the full scoped name "@modelcontextprotocol/server-*".
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.resolveMcpShorthand = resolveMcpShorthand;
|
|
10
|
+
exports.resolveAndLogMcpShorthand = resolveAndLogMcpShorthand;
|
|
11
|
+
const MCP_SCOPE = '@modelcontextprotocol';
|
|
12
|
+
/**
|
|
13
|
+
* Resolve a package name, expanding MCP shorthand if applicable.
|
|
14
|
+
*
|
|
15
|
+
* Rules (applied in order):
|
|
16
|
+
* 1. Starts with `@` -- use as-is (already scoped).
|
|
17
|
+
* 2. Starts with `server-` -- prefix with @modelcontextprotocol/.
|
|
18
|
+
* 3. Starts with `mcp/server-` or `mcp-server-` -- convert to @modelcontextprotocol/server-*.
|
|
19
|
+
* 4. Otherwise -- use as-is (regular npm package).
|
|
20
|
+
*/
|
|
21
|
+
function resolveMcpShorthand(name) {
|
|
22
|
+
if (name.startsWith('@'))
|
|
23
|
+
return name;
|
|
24
|
+
if (name.startsWith('server-'))
|
|
25
|
+
return `${MCP_SCOPE}/${name}`;
|
|
26
|
+
if (name.startsWith('mcp/server-'))
|
|
27
|
+
return `${MCP_SCOPE}/${name.slice('mcp/'.length)}`;
|
|
28
|
+
if (name.startsWith('mcp-server-'))
|
|
29
|
+
return `${MCP_SCOPE}/${name.slice('mcp-'.length)}`;
|
|
30
|
+
return name;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Resolve and log to stderr if the name changed.
|
|
34
|
+
*/
|
|
35
|
+
function resolveAndLogMcpShorthand(name) {
|
|
36
|
+
const resolved = resolveMcpShorthand(name);
|
|
37
|
+
if (resolved !== name) {
|
|
38
|
+
process.stderr.write(`Resolved: ${name} -> ${resolved}\n`);
|
|
39
|
+
}
|
|
40
|
+
return resolved;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=resolve-mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-mcp.js","sourceRoot":"","sources":["../src/resolve-mcp.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAaH,kDAMC;AAKD,8DAMC;AA5BD,MAAM,SAAS,GAAG,uBAAuB,CAAC;AAE1C;;;;;;;;GAQG;AACH,SAAgB,mBAAmB,CAAC,IAAY;IAC9C,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,GAAG,SAAS,IAAI,IAAI,EAAE,CAAC;IAC9D,IAAI,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;QAAE,OAAO,GAAG,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;IACvF,IAAI,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;QAAE,OAAO,GAAG,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;IACvF,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAgB,yBAAyB,CAAC,IAAY;IACpD,MAAM,QAAQ,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,IAAI,OAAO,QAAQ,IAAI,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -78,14 +78,14 @@ function generateId() {
|
|
|
78
78
|
}
|
|
79
79
|
function calculateGrade(score) {
|
|
80
80
|
if (score >= 90)
|
|
81
|
-
return '
|
|
81
|
+
return 'strong';
|
|
82
82
|
if (score >= 80)
|
|
83
|
-
return '
|
|
83
|
+
return 'good';
|
|
84
84
|
if (score >= 70)
|
|
85
|
-
return '
|
|
85
|
+
return 'moderate';
|
|
86
86
|
if (score >= 60)
|
|
87
|
-
return '
|
|
88
|
-
return '
|
|
87
|
+
return 'improving';
|
|
88
|
+
return 'needs-attention';
|
|
89
89
|
}
|
|
90
90
|
function isPrivateOrReserved(hostname) {
|
|
91
91
|
if (hostname === '169.254.169.254' || hostname === 'metadata.google.internal')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"external-scanner.js","sourceRoot":"","sources":["../../src/scanner/external-scanner.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,yCAA2B;AAC3B,2CAA6B;AAC7B,6CAA+B;AAG/B,wBAAwB;AACxB,MAAM,aAAa,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AAExF,6BAA6B;AAC7B,MAAM,YAAY,GAAG;IACnB,wBAAwB;IACxB,WAAW;IACX,mBAAmB;IACnB,mBAAmB;IACnB,cAAc;IACd,OAAO;CACR,CAAC;AAEF,8BAA8B;AAC9B,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC;AACrE,MAAM,eAAe,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;AAEvE,kBAAkB;AAClB,MAAM,eAAe,GAAG,CAAC,YAAY,EAAE,oBAAoB,CAAC,CAAC;AAE7D,mBAAmB;AACnB,MAAM,gBAAgB,GAAG;IACvB,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,mCAAmC,EAAE;IACnE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,yBAAyB,EAAE;IACtD,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,EAAE;IAClD,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE;IAC5C,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,EAAE;IAClD,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,4CAA4C,EAAE;CAC1E,CAAC;AAEF,+BAA+B;AAC/B,MAAM,gBAAgB,GAAoC;IACxD,QAAQ,EAAE,EAAE;IACZ,IAAI,EAAE,EAAE;IACR,MAAM,EAAE,EAAE;IACV,GAAG,EAAE,CAAC;CACP,CAAC;AAEF,SAAS,UAAU;IACjB,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"external-scanner.js","sourceRoot":"","sources":["../../src/scanner/external-scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Community Contribution Module
|
|
3
|
+
*
|
|
4
|
+
* Sends anonymized HMA scan findings to the OpenA2A Registry.
|
|
5
|
+
* No PII, no source code -- only check pass/fail results.
|
|
6
|
+
*/
|
|
7
|
+
import type { SecurityFinding } from '../hardening';
|
|
8
|
+
/** Anonymized finding sent to the registry. Only check ID, result, and severity. */
|
|
9
|
+
export interface ContributionFinding {
|
|
10
|
+
checkId: string;
|
|
11
|
+
result: 'pass' | 'fail';
|
|
12
|
+
severity: string;
|
|
13
|
+
}
|
|
14
|
+
/** Payload submitted to the telemetry endpoint. */
|
|
15
|
+
export interface ContributionPayload {
|
|
16
|
+
contributorToken: string;
|
|
17
|
+
packageName: string;
|
|
18
|
+
packageVersion: string;
|
|
19
|
+
ecosystem: 'npm' | 'pypi' | 'github';
|
|
20
|
+
scanTimestamp: string;
|
|
21
|
+
findings: ContributionFinding[];
|
|
22
|
+
hmaVersion: string;
|
|
23
|
+
osType: 'linux' | 'macos' | 'windows';
|
|
24
|
+
}
|
|
25
|
+
/** Result of submitting a contribution. */
|
|
26
|
+
export interface ContributionResult {
|
|
27
|
+
success: boolean;
|
|
28
|
+
scanId?: string;
|
|
29
|
+
error?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Generate a stable per-device contributor token.
|
|
33
|
+
*
|
|
34
|
+
* SHA256(hostname + username + random salt stored at ~/.opena2a/contributor-salt).
|
|
35
|
+
* The salt is generated once on first call and persisted locally.
|
|
36
|
+
*/
|
|
37
|
+
export declare function generateContributorToken(): string;
|
|
38
|
+
/**
|
|
39
|
+
* Build an anonymized contribution payload from scan findings.
|
|
40
|
+
*
|
|
41
|
+
* PRIVACY: This function intentionally strips all sensitive fields.
|
|
42
|
+
* The output contains ONLY: checkId, pass/fail result, and severity.
|
|
43
|
+
* No file paths, line numbers, descriptions, fix text, or code content.
|
|
44
|
+
*/
|
|
45
|
+
export declare function buildContributionPayload(packageName: string, packageVersion: string, ecosystem: 'npm' | 'pypi' | 'github', findings: SecurityFinding[]): ContributionPayload;
|
|
46
|
+
/**
|
|
47
|
+
* Build a contribution payload from scan findings, auto-detecting
|
|
48
|
+
* ecosystem and version from the target directory.
|
|
49
|
+
*
|
|
50
|
+
* Convenience wrapper around buildContributionPayload for CLI use.
|
|
51
|
+
*/
|
|
52
|
+
export declare function buildContributionPayloadFromDir(packageName: string, directory: string, findings: SecurityFinding[]): ContributionPayload;
|
|
53
|
+
/**
|
|
54
|
+
* Submit an anonymized contribution payload to the OpenA2A Registry.
|
|
55
|
+
*
|
|
56
|
+
* POST to https://api.oa2a.org/api/v1/telemetry/scan
|
|
57
|
+
* Timeout: 10 seconds. Non-blocking: failures are logged as warnings, never crash the scan.
|
|
58
|
+
*/
|
|
59
|
+
export declare function submitContribution(payload: ContributionPayload, registryUrl?: string): Promise<ContributionResult>;
|
|
60
|
+
//# sourceMappingURL=contribute.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contribute.d.ts","sourceRoot":"","sources":["../../src/telemetry/contribute.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,KAAK,EAAE,eAAe,EAAY,MAAM,cAAc,CAAC;AAE9D,oFAAoF;AACpF,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,mDAAmD;AACnD,MAAM,WAAW,mBAAmB;IAClC,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;CACvC;AAED,2CAA2C;AAC3C,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAUD;;;;;GAKG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAejD;AA4BD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,KAAK,GAAG,MAAM,GAAG,QAAQ,EACpC,QAAQ,EAAE,eAAe,EAAE,GAC1B,mBAAmB,CAiBrB;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC7C,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,eAAe,EAAE,GAC1B,mBAAmB,CAsBrB;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,mBAAmB,EAC5B,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,kBAAkB,CAAC,CAyC7B"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Community Contribution Module
|
|
4
|
+
*
|
|
5
|
+
* Sends anonymized HMA scan findings to the OpenA2A Registry.
|
|
6
|
+
* No PII, no source code -- only check pass/fail results.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.generateContributorToken = generateContributorToken;
|
|
10
|
+
exports.buildContributionPayload = buildContributionPayload;
|
|
11
|
+
exports.buildContributionPayloadFromDir = buildContributionPayloadFromDir;
|
|
12
|
+
exports.submitContribution = submitContribution;
|
|
13
|
+
const crypto_1 = require("crypto");
|
|
14
|
+
const fs_1 = require("fs");
|
|
15
|
+
const os_1 = require("os");
|
|
16
|
+
const path_1 = require("path");
|
|
17
|
+
const index_1 = require("../index");
|
|
18
|
+
/**
|
|
19
|
+
* Resolve the path to the OpenA2A home directory.
|
|
20
|
+
* Respects the OPENA2A_HOME env var, defaults to ~/.opena2a.
|
|
21
|
+
*/
|
|
22
|
+
function getOpena2aHome() {
|
|
23
|
+
return process.env.OPENA2A_HOME || (0, path_1.join)(require('os').homedir(), '.opena2a');
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Generate a stable per-device contributor token.
|
|
27
|
+
*
|
|
28
|
+
* SHA256(hostname + username + random salt stored at ~/.opena2a/contributor-salt).
|
|
29
|
+
* The salt is generated once on first call and persisted locally.
|
|
30
|
+
*/
|
|
31
|
+
function generateContributorToken() {
|
|
32
|
+
const home = getOpena2aHome();
|
|
33
|
+
const saltPath = (0, path_1.join)(home, 'contributor-salt');
|
|
34
|
+
let salt;
|
|
35
|
+
if ((0, fs_1.existsSync)(saltPath)) {
|
|
36
|
+
salt = (0, fs_1.readFileSync)(saltPath, 'utf-8').trim();
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
salt = (0, crypto_1.randomBytes)(32).toString('hex');
|
|
40
|
+
(0, fs_1.mkdirSync)(home, { recursive: true });
|
|
41
|
+
(0, fs_1.writeFileSync)(saltPath, salt, { mode: 0o600 });
|
|
42
|
+
}
|
|
43
|
+
const input = `${(0, os_1.hostname)()}|${(0, os_1.userInfo)().username}|${salt}`;
|
|
44
|
+
return (0, crypto_1.createHash)('sha256').update(input).digest('hex');
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Map the Node.js os.type() value to the server-accepted osType enum.
|
|
48
|
+
*/
|
|
49
|
+
function resolveOsType() {
|
|
50
|
+
const t = (0, os_1.type)();
|
|
51
|
+
if (t === 'Darwin')
|
|
52
|
+
return 'macos';
|
|
53
|
+
if (t === 'Windows_NT')
|
|
54
|
+
return 'windows';
|
|
55
|
+
return 'linux';
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Detect the package ecosystem from the target directory.
|
|
59
|
+
* Checks for package.json (npm), setup.py / pyproject.toml (pypi),
|
|
60
|
+
* or falls back to github.
|
|
61
|
+
*/
|
|
62
|
+
function detectEcosystem(directory) {
|
|
63
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(directory, 'package.json')))
|
|
64
|
+
return 'npm';
|
|
65
|
+
if ((0, fs_1.existsSync)((0, path_1.join)(directory, 'setup.py')) ||
|
|
66
|
+
(0, fs_1.existsSync)((0, path_1.join)(directory, 'pyproject.toml'))) {
|
|
67
|
+
return 'pypi';
|
|
68
|
+
}
|
|
69
|
+
return 'github';
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Build an anonymized contribution payload from scan findings.
|
|
73
|
+
*
|
|
74
|
+
* PRIVACY: This function intentionally strips all sensitive fields.
|
|
75
|
+
* The output contains ONLY: checkId, pass/fail result, and severity.
|
|
76
|
+
* No file paths, line numbers, descriptions, fix text, or code content.
|
|
77
|
+
*/
|
|
78
|
+
function buildContributionPayload(packageName, packageVersion, ecosystem, findings) {
|
|
79
|
+
const contributionFindings = findings.map((f) => ({
|
|
80
|
+
checkId: f.checkId,
|
|
81
|
+
result: f.passed ? 'pass' : 'fail',
|
|
82
|
+
severity: f.severity,
|
|
83
|
+
}));
|
|
84
|
+
return {
|
|
85
|
+
contributorToken: generateContributorToken(),
|
|
86
|
+
packageName,
|
|
87
|
+
packageVersion: packageVersion || '',
|
|
88
|
+
ecosystem,
|
|
89
|
+
scanTimestamp: new Date().toISOString(),
|
|
90
|
+
findings: contributionFindings,
|
|
91
|
+
hmaVersion: index_1.VERSION,
|
|
92
|
+
osType: resolveOsType(),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Build a contribution payload from scan findings, auto-detecting
|
|
97
|
+
* ecosystem and version from the target directory.
|
|
98
|
+
*
|
|
99
|
+
* Convenience wrapper around buildContributionPayload for CLI use.
|
|
100
|
+
*/
|
|
101
|
+
function buildContributionPayloadFromDir(packageName, directory, findings) {
|
|
102
|
+
let version = '';
|
|
103
|
+
const ecosystem = detectEcosystem(directory);
|
|
104
|
+
try {
|
|
105
|
+
if (ecosystem === 'npm') {
|
|
106
|
+
const pkg = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(directory, 'package.json'), 'utf-8'));
|
|
107
|
+
version = pkg.version || '';
|
|
108
|
+
}
|
|
109
|
+
else if (ecosystem === 'pypi') {
|
|
110
|
+
// Best-effort version detection from setup.py or pyproject.toml
|
|
111
|
+
const setupPath = (0, path_1.join)(directory, 'setup.py');
|
|
112
|
+
if ((0, fs_1.existsSync)(setupPath)) {
|
|
113
|
+
const content = (0, fs_1.readFileSync)(setupPath, 'utf-8');
|
|
114
|
+
const match = content.match(/version\s*=\s*['"]([^'"]+)['"]/);
|
|
115
|
+
if (match)
|
|
116
|
+
version = match[1];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
// Non-fatal: version detection is best-effort
|
|
122
|
+
}
|
|
123
|
+
return buildContributionPayload(packageName, version, ecosystem, findings);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Submit an anonymized contribution payload to the OpenA2A Registry.
|
|
127
|
+
*
|
|
128
|
+
* POST to https://api.oa2a.org/api/v1/telemetry/scan
|
|
129
|
+
* Timeout: 10 seconds. Non-blocking: failures are logged as warnings, never crash the scan.
|
|
130
|
+
*/
|
|
131
|
+
async function submitContribution(payload, registryUrl) {
|
|
132
|
+
const baseUrl = registryUrl || 'https://api.oa2a.org';
|
|
133
|
+
const url = `${baseUrl}/api/v1/telemetry/scan`;
|
|
134
|
+
try {
|
|
135
|
+
const controller = new AbortController();
|
|
136
|
+
const timeout = setTimeout(() => controller.abort(), 10000);
|
|
137
|
+
const response = await fetch(url, {
|
|
138
|
+
method: 'POST',
|
|
139
|
+
headers: {
|
|
140
|
+
'Content-Type': 'application/json',
|
|
141
|
+
'User-Agent': `HackMyAgent-CLI/${index_1.VERSION}`,
|
|
142
|
+
},
|
|
143
|
+
body: JSON.stringify(payload),
|
|
144
|
+
signal: controller.signal,
|
|
145
|
+
});
|
|
146
|
+
clearTimeout(timeout);
|
|
147
|
+
if (!response.ok) {
|
|
148
|
+
const body = await response.text().catch(() => '');
|
|
149
|
+
return {
|
|
150
|
+
success: false,
|
|
151
|
+
error: `HTTP ${response.status}: ${body}`.substring(0, 200),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
const result = (await response.json());
|
|
155
|
+
return {
|
|
156
|
+
success: true,
|
|
157
|
+
scanId: result.scanId || undefined,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
const message = err instanceof Error ? err.message : 'Unknown error';
|
|
162
|
+
// AbortError means timeout
|
|
163
|
+
if (message.includes('abort') || message.includes('Abort')) {
|
|
164
|
+
return { success: false, error: 'Request timed out (10s)' };
|
|
165
|
+
}
|
|
166
|
+
return { success: false, error: message };
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=contribute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contribute.js","sourceRoot":"","sources":["../../src/telemetry/contribute.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telemetry module -- community contribution of anonymized scan findings.
|
|
3
|
+
*/
|
|
4
|
+
export { generateContributorToken, buildContributionPayload, buildContributionPayloadFromDir, submitContribution, type ContributionFinding, type ContributionPayload, type ContributionResult, } from './contribute';
|
|
5
|
+
export { isContributeEnabled, shouldPromptContribute, incrementScanCount, saveContributeChoice, showContributePrompt, } from './opt-in';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/telemetry/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,wBAAwB,EACxB,wBAAwB,EACxB,+BAA+B,EAC/B,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,GACxB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,kBAAkB,EAClB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Telemetry module -- community contribution of anonymized scan findings.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.showContributePrompt = exports.saveContributeChoice = exports.incrementScanCount = exports.shouldPromptContribute = exports.isContributeEnabled = exports.submitContribution = exports.buildContributionPayloadFromDir = exports.buildContributionPayload = exports.generateContributorToken = void 0;
|
|
7
|
+
var contribute_1 = require("./contribute");
|
|
8
|
+
Object.defineProperty(exports, "generateContributorToken", { enumerable: true, get: function () { return contribute_1.generateContributorToken; } });
|
|
9
|
+
Object.defineProperty(exports, "buildContributionPayload", { enumerable: true, get: function () { return contribute_1.buildContributionPayload; } });
|
|
10
|
+
Object.defineProperty(exports, "buildContributionPayloadFromDir", { enumerable: true, get: function () { return contribute_1.buildContributionPayloadFromDir; } });
|
|
11
|
+
Object.defineProperty(exports, "submitContribution", { enumerable: true, get: function () { return contribute_1.submitContribution; } });
|
|
12
|
+
var opt_in_1 = require("./opt-in");
|
|
13
|
+
Object.defineProperty(exports, "isContributeEnabled", { enumerable: true, get: function () { return opt_in_1.isContributeEnabled; } });
|
|
14
|
+
Object.defineProperty(exports, "shouldPromptContribute", { enumerable: true, get: function () { return opt_in_1.shouldPromptContribute; } });
|
|
15
|
+
Object.defineProperty(exports, "incrementScanCount", { enumerable: true, get: function () { return opt_in_1.incrementScanCount; } });
|
|
16
|
+
Object.defineProperty(exports, "saveContributeChoice", { enumerable: true, get: function () { return opt_in_1.saveContributeChoice; } });
|
|
17
|
+
Object.defineProperty(exports, "showContributePrompt", { enumerable: true, get: function () { return opt_in_1.showContributePrompt; } });
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/telemetry/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,2CAQsB;AAPpB,sHAAA,wBAAwB,OAAA;AACxB,sHAAA,wBAAwB,OAAA;AACxB,6HAAA,+BAA+B,OAAA;AAC/B,gHAAA,kBAAkB,OAAA;AAMpB,mCAMkB;AALhB,6GAAA,mBAAmB,OAAA;AACnB,gHAAA,sBAAsB,OAAA;AACtB,4GAAA,kBAAkB,OAAA;AAClB,8GAAA,oBAAoB,OAAA;AACpB,8GAAA,oBAAoB,OAAA"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contribution Opt-In Prompt
|
|
3
|
+
*
|
|
4
|
+
* Handles the user's consent to share anonymized scan findings
|
|
5
|
+
* with the OpenA2A Registry.
|
|
6
|
+
*
|
|
7
|
+
* Config/counting is delegated to @opena2a/shared (the canonical
|
|
8
|
+
* source for ~/.opena2a/config.json). If @opena2a/shared is not
|
|
9
|
+
* available at runtime, falls back to a local implementation.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Check whether the contribution setting is enabled.
|
|
13
|
+
*
|
|
14
|
+
* Returns:
|
|
15
|
+
* true - user explicitly opted in
|
|
16
|
+
* false - user explicitly opted out (or default in shared backend)
|
|
17
|
+
* undefined - not yet configured (local fallback only; shared backend
|
|
18
|
+
* defaults to false, so callers should rely on
|
|
19
|
+
* shouldPromptContribute() for prompt logic)
|
|
20
|
+
*/
|
|
21
|
+
export declare function isContributeEnabled(): boolean | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Check whether we should show the contribution prompt.
|
|
24
|
+
*
|
|
25
|
+
* HMA-specific: also checks for TTY (non-interactive environments
|
|
26
|
+
* should never prompt). The backend handles scan-count thresholds
|
|
27
|
+
* and cooldown/dismiss logic.
|
|
28
|
+
*/
|
|
29
|
+
export declare function shouldPromptContribute(): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Increment the scan count. Called after each scan completes,
|
|
32
|
+
* regardless of contribution setting.
|
|
33
|
+
*/
|
|
34
|
+
export declare function incrementScanCount(): void;
|
|
35
|
+
/**
|
|
36
|
+
* Save the user's contribution choice to the config file.
|
|
37
|
+
*/
|
|
38
|
+
export declare function saveContributeChoice(enabled: boolean): void;
|
|
39
|
+
/**
|
|
40
|
+
* Display the contribution opt-in prompt and return the user's choice.
|
|
41
|
+
*
|
|
42
|
+
* Uses raw stdin to read a single keypress (Y/N).
|
|
43
|
+
* Returns true if the user opted in, false otherwise.
|
|
44
|
+
*/
|
|
45
|
+
export declare function showContributePrompt(): Promise<boolean>;
|
|
46
|
+
//# sourceMappingURL=opt-in.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opt-in.d.ts","sourceRoot":"","sources":["../../src/telemetry/opt-in.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAsIH;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,GAAG,SAAS,CAEzD;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAGhD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAK3D;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC,CA2B7D"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Contribution Opt-In Prompt
|
|
4
|
+
*
|
|
5
|
+
* Handles the user's consent to share anonymized scan findings
|
|
6
|
+
* with the OpenA2A Registry.
|
|
7
|
+
*
|
|
8
|
+
* Config/counting is delegated to @opena2a/shared (the canonical
|
|
9
|
+
* source for ~/.opena2a/config.json). If @opena2a/shared is not
|
|
10
|
+
* available at runtime, falls back to a local implementation.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.isContributeEnabled = isContributeEnabled;
|
|
14
|
+
exports.shouldPromptContribute = shouldPromptContribute;
|
|
15
|
+
exports.incrementScanCount = incrementScanCount;
|
|
16
|
+
exports.saveContributeChoice = saveContributeChoice;
|
|
17
|
+
exports.showContributePrompt = showContributePrompt;
|
|
18
|
+
const fs_1 = require("fs");
|
|
19
|
+
const path_1 = require("path");
|
|
20
|
+
/** Resolved backend -- lazy-initialized on first call. */
|
|
21
|
+
let _backend;
|
|
22
|
+
function resolveBackend() {
|
|
23
|
+
if (_backend)
|
|
24
|
+
return _backend;
|
|
25
|
+
try {
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
27
|
+
const shared = require('@opena2a/shared');
|
|
28
|
+
if (typeof shared.isContributeEnabled === 'function' &&
|
|
29
|
+
typeof shared.setContributeEnabled === 'function' &&
|
|
30
|
+
typeof shared.incrementScanCount === 'function' &&
|
|
31
|
+
typeof shared.shouldPromptContribute === 'function' &&
|
|
32
|
+
typeof shared.dismissContributePrompt === 'function') {
|
|
33
|
+
_backend = {
|
|
34
|
+
isContributeEnabled: shared.isContributeEnabled,
|
|
35
|
+
setContributeEnabled: shared.setContributeEnabled,
|
|
36
|
+
incrementScanCount: shared.incrementScanCount,
|
|
37
|
+
shouldPromptContribute: shared.shouldPromptContribute,
|
|
38
|
+
dismissContributePrompt: shared.dismissContributePrompt,
|
|
39
|
+
};
|
|
40
|
+
return _backend;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// @opena2a/shared not installed -- fall through to local backend
|
|
45
|
+
}
|
|
46
|
+
_backend = createLocalBackend();
|
|
47
|
+
return _backend;
|
|
48
|
+
}
|
|
49
|
+
function getConfigPath() {
|
|
50
|
+
const home = process.env.OPENA2A_HOME || (0, path_1.join)(require('os').homedir(), '.opena2a');
|
|
51
|
+
return (0, path_1.join)(home, 'config.json');
|
|
52
|
+
}
|
|
53
|
+
function readConfig() {
|
|
54
|
+
const configPath = getConfigPath();
|
|
55
|
+
try {
|
|
56
|
+
if ((0, fs_1.existsSync)(configPath)) {
|
|
57
|
+
return JSON.parse((0, fs_1.readFileSync)(configPath, 'utf-8'));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Corrupt config -- treat as empty
|
|
62
|
+
}
|
|
63
|
+
return {};
|
|
64
|
+
}
|
|
65
|
+
function writeConfig(config) {
|
|
66
|
+
const configPath = getConfigPath();
|
|
67
|
+
const dir = require('path').dirname(configPath);
|
|
68
|
+
(0, fs_1.mkdirSync)(dir, { recursive: true });
|
|
69
|
+
(0, fs_1.writeFileSync)(configPath, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
|
|
70
|
+
}
|
|
71
|
+
function createLocalBackend() {
|
|
72
|
+
return {
|
|
73
|
+
isContributeEnabled() {
|
|
74
|
+
const config = readConfig();
|
|
75
|
+
return config.contribute?.enabled === true;
|
|
76
|
+
},
|
|
77
|
+
setContributeEnabled(enabled) {
|
|
78
|
+
const config = readConfig();
|
|
79
|
+
if (!config.contribute)
|
|
80
|
+
config.contribute = {};
|
|
81
|
+
config.contribute.enabled = enabled;
|
|
82
|
+
const scanCount = config.contribute.scanCount ?? 0;
|
|
83
|
+
if (scanCount >= 9)
|
|
84
|
+
config.contribute.promptedAtTen = true;
|
|
85
|
+
writeConfig(config);
|
|
86
|
+
},
|
|
87
|
+
incrementScanCount() {
|
|
88
|
+
const config = readConfig();
|
|
89
|
+
if (!config.contribute)
|
|
90
|
+
config.contribute = {};
|
|
91
|
+
config.contribute.scanCount = (config.contribute.scanCount ?? 0) + 1;
|
|
92
|
+
writeConfig(config);
|
|
93
|
+
return config.contribute.scanCount;
|
|
94
|
+
},
|
|
95
|
+
shouldPromptContribute() {
|
|
96
|
+
const config = readConfig();
|
|
97
|
+
if (config.contribute?.enabled === true || config.contribute?.enabled === false)
|
|
98
|
+
return false;
|
|
99
|
+
const scanCount = config.contribute?.scanCount ?? 0;
|
|
100
|
+
if (scanCount === 0)
|
|
101
|
+
return true;
|
|
102
|
+
if (scanCount >= 9 && !config.contribute?.promptedAtTen)
|
|
103
|
+
return true;
|
|
104
|
+
return false;
|
|
105
|
+
},
|
|
106
|
+
dismissContributePrompt() {
|
|
107
|
+
const config = readConfig();
|
|
108
|
+
if (!config.contribute)
|
|
109
|
+
config.contribute = {};
|
|
110
|
+
config.contribute.promptedAtTen = true;
|
|
111
|
+
writeConfig(config);
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
// Public API (signatures preserved for backward compatibility)
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
/**
|
|
119
|
+
* Check whether the contribution setting is enabled.
|
|
120
|
+
*
|
|
121
|
+
* Returns:
|
|
122
|
+
* true - user explicitly opted in
|
|
123
|
+
* false - user explicitly opted out (or default in shared backend)
|
|
124
|
+
* undefined - not yet configured (local fallback only; shared backend
|
|
125
|
+
* defaults to false, so callers should rely on
|
|
126
|
+
* shouldPromptContribute() for prompt logic)
|
|
127
|
+
*/
|
|
128
|
+
function isContributeEnabled() {
|
|
129
|
+
return resolveBackend().isContributeEnabled() || undefined;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Check whether we should show the contribution prompt.
|
|
133
|
+
*
|
|
134
|
+
* HMA-specific: also checks for TTY (non-interactive environments
|
|
135
|
+
* should never prompt). The backend handles scan-count thresholds
|
|
136
|
+
* and cooldown/dismiss logic.
|
|
137
|
+
*/
|
|
138
|
+
function shouldPromptContribute() {
|
|
139
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
140
|
+
return false;
|
|
141
|
+
return resolveBackend().shouldPromptContribute();
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Increment the scan count. Called after each scan completes,
|
|
145
|
+
* regardless of contribution setting.
|
|
146
|
+
*/
|
|
147
|
+
function incrementScanCount() {
|
|
148
|
+
resolveBackend().incrementScanCount();
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Save the user's contribution choice to the config file.
|
|
152
|
+
*/
|
|
153
|
+
function saveContributeChoice(enabled) {
|
|
154
|
+
resolveBackend().setContributeEnabled(enabled);
|
|
155
|
+
if (!enabled) {
|
|
156
|
+
resolveBackend().dismissContributePrompt();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Display the contribution opt-in prompt and return the user's choice.
|
|
161
|
+
*
|
|
162
|
+
* Uses raw stdin to read a single keypress (Y/N).
|
|
163
|
+
* Returns true if the user opted in, false otherwise.
|
|
164
|
+
*/
|
|
165
|
+
async function showContributePrompt() {
|
|
166
|
+
const lines = [
|
|
167
|
+
'',
|
|
168
|
+
'Help improve security for the AI agent community.',
|
|
169
|
+
'',
|
|
170
|
+
'Share anonymized scan findings with the OpenA2A Registry?',
|
|
171
|
+
'No personal data. No source code. Only check pass/fail results.',
|
|
172
|
+
'You can opt out anytime: opena2a config set contribute false',
|
|
173
|
+
'',
|
|
174
|
+
'[Y] Yes, contribute [N] No thanks',
|
|
175
|
+
];
|
|
176
|
+
for (const line of lines) {
|
|
177
|
+
process.stdout.write(line + '\n');
|
|
178
|
+
}
|
|
179
|
+
const answer = await readSingleKey();
|
|
180
|
+
const enabled = answer.toLowerCase() === 'y';
|
|
181
|
+
saveContributeChoice(enabled);
|
|
182
|
+
if (enabled) {
|
|
183
|
+
process.stdout.write('\nContribution enabled. Thank you.\n');
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
process.stdout.write('\nContribution disabled. You can enable it later: opena2a config set contribute true\n');
|
|
187
|
+
}
|
|
188
|
+
return enabled;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Read a single keypress from stdin.
|
|
192
|
+
* Falls back to 'n' after a 30-second timeout.
|
|
193
|
+
*/
|
|
194
|
+
function readSingleKey() {
|
|
195
|
+
return new Promise((resolve) => {
|
|
196
|
+
const stdin = process.stdin;
|
|
197
|
+
const wasRaw = stdin.isRaw;
|
|
198
|
+
const timer = setTimeout(() => {
|
|
199
|
+
cleanup();
|
|
200
|
+
resolve('n');
|
|
201
|
+
}, 30000);
|
|
202
|
+
function cleanup() {
|
|
203
|
+
clearTimeout(timer);
|
|
204
|
+
stdin.removeListener('data', onData);
|
|
205
|
+
if (stdin.isRaw !== wasRaw) {
|
|
206
|
+
stdin.setRawMode(wasRaw ?? false);
|
|
207
|
+
}
|
|
208
|
+
stdin.pause();
|
|
209
|
+
}
|
|
210
|
+
function onData(data) {
|
|
211
|
+
const char = data.toString().trim().toLowerCase();
|
|
212
|
+
cleanup();
|
|
213
|
+
resolve(char || 'n');
|
|
214
|
+
}
|
|
215
|
+
stdin.setRawMode(true);
|
|
216
|
+
stdin.resume();
|
|
217
|
+
stdin.once('data', onData);
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=opt-in.js.map
|