hackmyagent 0.17.1 → 0.17.2

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/dist/cli.js CHANGED
@@ -2268,6 +2268,7 @@ Examples:
2268
2268
  .option('-l, --level <level>', 'Benchmark level: L1 (Essential), L2 (Standard), L3 (Hardened)', 'L1')
2269
2269
  .option('-c, --category <name>', 'Filter to specific benchmark category')
2270
2270
  .option('--deep', 'Maximum analysis: static + semantic + behavioral simulation + adaptive attacks (~30s per file)')
2271
+ .option('--analm', 'AI-powered threat analysis using AnaLM (requires analm setup)')
2271
2272
  .option('--static-only', 'Disable semantic analysis and simulation (static checks only, fast, deterministic)')
2272
2273
  .option('--scan-depth <depth>', 'CAAT scan depth: quick (config+creds only), standard (default), deep (+ simulation)', 'standard')
2273
2274
  .option('--ci-publish', 'Submit scan results to registry CI endpoint (requires CI_SCAN_HMAC_SECRET env)')
@@ -2360,7 +2361,7 @@ Examples:
2360
2361
  catch { /* daemon not installed */ }
2361
2362
  }
2362
2363
  const onProgress = format === 'text'
2363
- ? (msg) => process.stdout.write(msg)
2364
+ ? (msg) => process.stdout.write(msg.endsWith('\n') ? msg : msg + '\n')
2364
2365
  : undefined;
2365
2366
  // Show analysis mode to user
2366
2367
  if (format === 'text') {
@@ -2396,15 +2397,16 @@ Examples:
2396
2397
  const scanDurationMs = Date.now() - scanStartMs;
2397
2398
  // NanoMind Semantic Compiler: AST-based analysis runs alongside static checks
2398
2399
  // Defense-in-depth: static findings can NEVER be suppressed, only upgraded
2400
+ const { orchestrateNanoMind } = await Promise.resolve().then(() => __importStar(require('./nanomind-core/orchestrate.js')));
2401
+ const existingFindings = result.allFindings || result.findings || [];
2402
+ const nmResult = await orchestrateNanoMind(targetDir, existingFindings, {
2403
+ staticOnly: isStaticOnly,
2404
+ ci: options.ci,
2405
+ deep: isDeep,
2406
+ analm: options.analm,
2407
+ silent: format !== 'text',
2408
+ });
2399
2409
  {
2400
- const { orchestrateNanoMind } = await Promise.resolve().then(() => __importStar(require('./nanomind-core/orchestrate.js')));
2401
- const existingFindings = result.allFindings || result.findings || [];
2402
- const nmResult = await orchestrateNanoMind(targetDir, existingFindings, {
2403
- staticOnly: isStaticOnly,
2404
- ci: options.ci,
2405
- deep: isDeep,
2406
- silent: format !== 'text',
2407
- });
2408
2410
  // Re-apply all filters after NanoMind merge (merge uses allFindings which is unfiltered)
2409
2411
  const refiltered = await scanner.reapplyIgnoreFilters(nmResult.mergedFindings, targetDir);
2410
2412
  if (result.allFindings) {
@@ -2593,7 +2595,10 @@ Examples:
2593
2595
  publishStatus = { success: false, error: msg };
2594
2596
  }
2595
2597
  }
2596
- const jsonOutput = publishStatus ? { ...result, publish: publishStatus } : result;
2598
+ const jsonBase = nmResult.analystFindings?.length
2599
+ ? { ...result, analystFindings: nmResult.analystFindings }
2600
+ : result;
2601
+ const jsonOutput = publishStatus ? { ...jsonBase, publish: publishStatus } : jsonBase;
2597
2602
  if (options.output) {
2598
2603
  require('fs').writeFileSync(options.output, JSON.stringify(jsonOutput, null, 2) + '\n');
2599
2604
  console.error(`Report written to ${options.output}`);
@@ -2748,6 +2753,42 @@ Examples:
2748
2753
  if (summaryParts.length > 0) {
2749
2754
  console.log(`${summaryParts.join(' | ')}\n`);
2750
2755
  }
2756
+ // Analyst findings (--analyze)
2757
+ if (nmResult.analystFindings && nmResult.analystFindings.length > 0) {
2758
+ console.log(`${colors.cyan}--- AnaLM Analysis ---${RESET()}\n`);
2759
+ for (const af of nmResult.analystFindings) {
2760
+ const r = af.result;
2761
+ if (af.taskType === 'threatAnalysis') {
2762
+ const level = String(r.threatLevel ?? 'unknown').toUpperCase();
2763
+ const levelColor = level === 'CRITICAL' || level === 'HIGH' ? colors.red : level === 'MEDIUM' ? colors.yellow : colors.dim;
2764
+ console.log(` ${levelColor}${level}${RESET()} ${r.attackVector ?? ''}`);
2765
+ if (r.description)
2766
+ console.log(` ${r.description}`);
2767
+ if (Array.isArray(r.mitigations) && r.mitigations.length > 0) {
2768
+ for (const m of r.mitigations) {
2769
+ console.log(` ${colors.cyan}Fix:${RESET()} ${m}`);
2770
+ }
2771
+ }
2772
+ }
2773
+ else if (af.taskType === 'credentialContextClassification') {
2774
+ const cls = String(r.classification ?? 'unknown');
2775
+ const clsColor = cls === 'real' ? colors.red : cls === 'test' || cls === 'example' ? colors.green : colors.yellow;
2776
+ console.log(` Credential: ${clsColor}${cls}${RESET()}`);
2777
+ if (r.reasoning)
2778
+ console.log(` ${r.reasoning}`);
2779
+ }
2780
+ else {
2781
+ // Generic display for other task types
2782
+ console.log(` ${af.taskType}: ${JSON.stringify(r)}`);
2783
+ }
2784
+ console.log(` ${colors.dim}Confidence: ${Math.round(af.confidence * 100)}% | ${af.modelVersion} (${af.durationMs}ms)${RESET()}`);
2785
+ console.log();
2786
+ }
2787
+ }
2788
+ // Analyst hint (shown when model is available but --analyze not used)
2789
+ if (nmResult.analystHint && issues.length > 0) {
2790
+ console.log(`${colors.dim}Tip: ${nmResult.analystHint}${RESET()}\n`);
2791
+ }
2751
2792
  // Dry-run summary
2752
2793
  if (result.dryRun) {
2753
2794
  const wouldFixCount = issues.filter((f) => f.wouldFix).length;
@@ -2798,7 +2839,8 @@ Examples:
2798
2839
  console.error('Error: --registry-key or REGISTRY_API_KEY env is required when using --version-id');
2799
2840
  process.exit(1);
2800
2841
  }
2801
- const client = new core.RegistryClient({ registryUrl, apiKey: registryKey });
2842
+ const atcToken = process.env.ATC_TOKEN;
2843
+ const client = new core.RegistryClient({ registryUrl, apiKey: registryKey, atcToken });
2802
2844
  const payload = core.buildScanReport(options.versionId, result.findings);
2803
2845
  await client.reportScanResult(payload);
2804
2846
  console.log(`Registry: scan results reported for version ${options.versionId}`);
@@ -3568,7 +3610,8 @@ Examples:
3568
3610
  console.error('Error: --registry-key or REGISTRY_API_KEY env is required when using --version-id');
3569
3611
  process.exit(1);
3570
3612
  }
3571
- const client = new core.RegistryClient({ registryUrl, apiKey: registryKey });
3613
+ const atcToken = process.env.ATC_TOKEN;
3614
+ const client = new core.RegistryClient({ registryUrl, apiKey: registryKey, atcToken });
3572
3615
  const payload = core.buildAttackReport(options.versionId, report);
3573
3616
  await client.reportScanResult(payload);
3574
3617
  console.log(`Registry: attack results reported for version ${options.versionId}`);
@@ -6118,6 +6161,63 @@ program
6118
6161
  }
6119
6162
  console.log(`\nYour skill is ready. Verify security with: hackmyagent secure ${outputDir}/`);
6120
6163
  });
6164
+ // analm: manage the AnaLM generative model
6165
+ const analmCmd = program
6166
+ .command('analm')
6167
+ .description('Manage the AnaLM model for AI-powered security analysis');
6168
+ analmCmd
6169
+ .command('setup')
6170
+ .description('Download the AnaLM model')
6171
+ .action(async () => {
6172
+ const { getAnalystStatus, setupAnalystModel } = await Promise.resolve().then(() => __importStar(require('./nanomind-core/inference/security-analyst.js')));
6173
+ const status = await getAnalystStatus();
6174
+ console.log('AnaLM (NanoMind Security Analyst)');
6175
+ console.log(` Platform: ${status.platform}`);
6176
+ console.log(` Backend: ${status.backend === 'none' ? 'not available' : status.backend}`);
6177
+ console.log(` Model: ${status.modelCached ? 'cached' : 'not downloaded'}`);
6178
+ console.log('');
6179
+ if (status.backend === 'none') {
6180
+ console.log('No supported inference backend found.');
6181
+ if (process.platform !== 'darwin') {
6182
+ console.log('Currently requires Apple Silicon Mac with MLX.');
6183
+ console.log('Cross-platform support (llama.cpp/GGUF) coming soon.');
6184
+ }
6185
+ else {
6186
+ console.log('Install uv: curl -LsSf https://astral.sh/uv/install.sh | sh');
6187
+ }
6188
+ process.exit(1);
6189
+ }
6190
+ if (status.modelCached) {
6191
+ console.log('Model already downloaded. Use --analm with any scan command.');
6192
+ return;
6193
+ }
6194
+ const ok = await setupAnalystModel(false);
6195
+ if (!ok)
6196
+ process.exit(1);
6197
+ });
6198
+ analmCmd
6199
+ .command('status')
6200
+ .description('Check the status of AnaLM model and runtime')
6201
+ .action(async () => {
6202
+ const { getAnalystStatus } = await Promise.resolve().then(() => __importStar(require('./nanomind-core/inference/security-analyst.js')));
6203
+ const status = await getAnalystStatus();
6204
+ console.log('AnaLM (NanoMind Security Analyst)');
6205
+ console.log(` Platform: ${status.platform}`);
6206
+ console.log(` Backend: ${status.backend === 'none' ? `${colors.red}not available${RESET()}` : `${colors.green}${status.backend}${RESET()}`}`);
6207
+ console.log(` Model: ${status.modelCached ? `${colors.green}cached${RESET()}` : `${colors.yellow}not downloaded${RESET()}`}`);
6208
+ console.log(` Ready: ${status.available ? `${colors.green}yes${RESET()}` : `${colors.yellow}no${RESET()}`}`);
6209
+ console.log('');
6210
+ if (status.available) {
6211
+ console.log('Use --analm with any scan command for AI-powered analysis.');
6212
+ console.log(` Example: hackmyagent secure ./my-agent --analm`);
6213
+ }
6214
+ else if (status.backend !== 'none') {
6215
+ console.log(`Run: hackmyagent analm setup`);
6216
+ }
6217
+ else if (process.platform !== 'darwin') {
6218
+ console.log('Cross-platform support (llama.cpp/GGUF) coming soon.');
6219
+ }
6220
+ });
6121
6221
  // ============================================================================
6122
6222
  // npm package scanning helpers (used by `check <package>`)
6123
6223
  // ============================================================================