hackmyagent 0.9.4 → 0.9.5
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 +70 -23
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/soul/index.d.ts +2 -2
- package/dist/soul/index.d.ts.map +1 -1
- package/dist/soul/index.js +2 -1
- package/dist/soul/index.js.map +1 -1
- package/dist/soul/scanner.d.ts +36 -3
- package/dist/soul/scanner.d.ts.map +1 -1
- package/dist/soul/scanner.js +326 -102
- package/dist/soul/scanner.js.map +1 -1
- package/dist/soul/templates.d.ts +4 -0
- package/dist/soul/templates.d.ts.map +1 -1
- package/dist/soul/templates.js +217 -0
- package/dist/soul/templates.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3591,6 +3591,35 @@ function gradeColor(grade) {
|
|
|
3591
3591
|
case 'F': return colors.brightRed;
|
|
3592
3592
|
}
|
|
3593
3593
|
}
|
|
3594
|
+
function levelColor(level) {
|
|
3595
|
+
switch (level) {
|
|
3596
|
+
case 'hardened': return colors.green;
|
|
3597
|
+
case 'standard': return colors.green;
|
|
3598
|
+
case 'developing': return colors.yellow;
|
|
3599
|
+
case 'initial': return colors.cyan;
|
|
3600
|
+
case 'not-started': return colors.reset;
|
|
3601
|
+
}
|
|
3602
|
+
}
|
|
3603
|
+
function levelLabel(level) {
|
|
3604
|
+
switch (level) {
|
|
3605
|
+
case 'hardened': return 'Hardened';
|
|
3606
|
+
case 'standard': return 'Standard';
|
|
3607
|
+
case 'developing': return 'Developing';
|
|
3608
|
+
case 'initial': return 'Initial';
|
|
3609
|
+
case 'not-started': return 'Not Started';
|
|
3610
|
+
}
|
|
3611
|
+
}
|
|
3612
|
+
/**
|
|
3613
|
+
* Detect how the CLI was invoked to suggest correct command prefix.
|
|
3614
|
+
*/
|
|
3615
|
+
function getCommandPrefix() {
|
|
3616
|
+
const execPath = process.argv[1] || '';
|
|
3617
|
+
if (execPath.includes('npx') || execPath.includes('.npm/_npx') ||
|
|
3618
|
+
execPath.includes('node_modules/.bin')) {
|
|
3619
|
+
return 'npx hackmyagent';
|
|
3620
|
+
}
|
|
3621
|
+
return 'hackmyagent';
|
|
3622
|
+
}
|
|
3594
3623
|
// Domain percentage bar for text output
|
|
3595
3624
|
function domainBar(pct) {
|
|
3596
3625
|
if (pct >= 80)
|
|
@@ -3613,31 +3642,29 @@ Searches for governance files in priority order:
|
|
|
3613
3642
|
> .github/copilot-instructions.md > CLAUDE.md > .clinerules
|
|
3614
3643
|
> instructions.md > constitution.md > agent-config.yaml
|
|
3615
3644
|
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3645
|
+
Agent profiles filter domains by agent purpose:
|
|
3646
|
+
conversational: Injection, Hardcoded, Honesty
|
|
3647
|
+
code-assistant: + Trust, Data
|
|
3648
|
+
tool-agent: + Capability, Oversight
|
|
3649
|
+
autonomous: + Agentic Safety
|
|
3650
|
+
orchestrator: All 8 domains
|
|
3621
3651
|
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
Conformance levels:
|
|
3626
|
-
none: one or more critical controls missing
|
|
3627
|
-
essential: all critical controls pass, score < 60
|
|
3628
|
-
standard: all critical controls pass, score >= 60
|
|
3629
|
-
hardened: all critical controls pass, score >= 75
|
|
3652
|
+
Maturity levels:
|
|
3653
|
+
Hardened (80+), Standard (60-79), Developing (40-59),
|
|
3654
|
+
Initial (1-39), Not Started (0)
|
|
3630
3655
|
|
|
3631
3656
|
Examples:
|
|
3632
3657
|
$ hackmyagent scan-soul Scan current directory
|
|
3633
3658
|
$ hackmyagent scan-soul ./my-agent Scan specific directory
|
|
3634
3659
|
$ hackmyagent scan-soul --json Machine-readable output
|
|
3635
3660
|
$ hackmyagent scan-soul --verbose Show all controls
|
|
3661
|
+
$ hackmyagent scan-soul --profile conversational Override profile
|
|
3636
3662
|
$ hackmyagent scan-soul --deep Enable LLM semantic analysis`)
|
|
3637
3663
|
.argument('[directory]', 'Directory to scan (defaults to current directory)', '.')
|
|
3638
3664
|
.option('--json', 'Output as JSON')
|
|
3639
3665
|
.option('-v, --verbose', 'Show individual control results')
|
|
3640
3666
|
.option('--tier <tier>', 'Override agent tier detection (BASIC, TOOL-USING, AGENTIC, MULTI-AGENT)')
|
|
3667
|
+
.option('--profile <profile>', 'Override agent profile (conversational, code-assistant, tool-agent, autonomous, orchestrator, custom)')
|
|
3641
3668
|
.option('--fail-below <score>', 'Exit 1 if score below threshold (0-100)')
|
|
3642
3669
|
.option('--deep', 'Enable LLM semantic analysis for ambiguous controls (requires claude CLI or ANTHROPIC_API_KEY)')
|
|
3643
3670
|
.action(async (directory, options) => {
|
|
@@ -3647,10 +3674,12 @@ Examples:
|
|
|
3647
3674
|
process.stderr.write(`Error: Directory '${targetDir}' does not exist.\n`);
|
|
3648
3675
|
process.exit(1);
|
|
3649
3676
|
}
|
|
3677
|
+
const prefix = getCommandPrefix();
|
|
3650
3678
|
const scanner = new index_1.SoulScanner();
|
|
3651
3679
|
const result = await scanner.scanSoul(targetDir, {
|
|
3652
3680
|
verbose: options.verbose,
|
|
3653
3681
|
tier: options.tier,
|
|
3682
|
+
profile: options.profile,
|
|
3654
3683
|
deepAnalysis: options.deep,
|
|
3655
3684
|
});
|
|
3656
3685
|
// JSON output
|
|
@@ -3676,9 +3705,22 @@ Examples:
|
|
|
3676
3705
|
process.stdout.write(` Searched: ${['SOUL.md', 'system-prompt.md', 'CLAUDE.md', '...'].join(', ')}\n`);
|
|
3677
3706
|
}
|
|
3678
3707
|
const tierLabel = result.tierForced ? `${result.agentTier} (--tier flag)` : `${result.agentTier} (auto-detected)`;
|
|
3679
|
-
|
|
3708
|
+
const profileLabel = result.profileForced ? `${result.agentProfile} (--profile flag)` : `${result.agentProfile} (auto-detected)`;
|
|
3709
|
+
process.stdout.write(`Agent Tier: ${tierLabel}\n`);
|
|
3710
|
+
process.stdout.write(`Agent Profile: ${profileLabel}\n`);
|
|
3711
|
+
if (result.skippedDomains.length > 0) {
|
|
3712
|
+
process.stdout.write(`Skipped Domains: ${result.skippedDomains.join(', ')}\n`);
|
|
3713
|
+
}
|
|
3714
|
+
process.stdout.write('\n');
|
|
3680
3715
|
process.stdout.write('Domain Scores:\n');
|
|
3681
3716
|
for (const domain of result.domains) {
|
|
3717
|
+
if (domain.skippedByProfile) {
|
|
3718
|
+
if (options.verbose) {
|
|
3719
|
+
const label = (domain.domain + ':').padEnd(26);
|
|
3720
|
+
process.stdout.write(` ${label}${colors.reset}-- (skipped by profile)${colors.reset}\n`);
|
|
3721
|
+
}
|
|
3722
|
+
continue;
|
|
3723
|
+
}
|
|
3682
3724
|
const pctColor = domainBar(domain.percentage);
|
|
3683
3725
|
const label = (domain.domain + ':').padEnd(26);
|
|
3684
3726
|
process.stdout.write(` ${label}${pctColor}${domain.passed}/${domain.total} (${domain.percentage}%)${colors.reset}\n`);
|
|
@@ -3693,9 +3735,9 @@ Examples:
|
|
|
3693
3735
|
}
|
|
3694
3736
|
}
|
|
3695
3737
|
process.stdout.write('\n');
|
|
3696
|
-
// Score and
|
|
3697
|
-
const
|
|
3698
|
-
process.stdout.write(`Governance Score: ${
|
|
3738
|
+
// Score and level (progress-oriented)
|
|
3739
|
+
const lc = levelColor(result.level);
|
|
3740
|
+
process.stdout.write(`Governance Score: ${lc}${result.score}/100 [${levelLabel(result.level)}]${colors.reset}\n`);
|
|
3699
3741
|
// Conformance level
|
|
3700
3742
|
if (result.conformance === 'none') {
|
|
3701
3743
|
process.stdout.write(`Conformance: ${colors.red}NONE${colors.reset} -- critical control missing (${result.criticalMissing.join(', ')})\n`);
|
|
@@ -3714,11 +3756,12 @@ Examples:
|
|
|
3714
3756
|
const llmUpgraded = result.deepAnalysisResults.filter((e) => e.llmPassed).length;
|
|
3715
3757
|
process.stdout.write(`Deep Analysis: ${llmUpgraded} control${llmUpgraded === 1 ? '' : 's'} upgraded by LLM semantic analysis\n`);
|
|
3716
3758
|
}
|
|
3717
|
-
// Path forward
|
|
3759
|
+
// Path forward (recovery-oriented, not punitive)
|
|
3718
3760
|
const missing = result.totalControls - result.totalPassed;
|
|
3719
3761
|
if (missing > 0) {
|
|
3720
|
-
|
|
3721
|
-
process.stdout.write(
|
|
3762
|
+
const recoverable = Math.min(100 - result.score, 100);
|
|
3763
|
+
process.stdout.write(`\n Path forward: +${recoverable} recoverable by addressing ${missing} control${missing === 1 ? '' : 's'}`);
|
|
3764
|
+
process.stdout.write(`\n Run '${colors.cyan}${prefix} harden-soul${colors.reset}' to remediate.\n`);
|
|
3722
3765
|
}
|
|
3723
3766
|
else {
|
|
3724
3767
|
process.stdout.write(`\n${colors.green}All ${result.totalControls} governance controls covered.${colors.reset}\n`);
|
|
@@ -3744,6 +3787,8 @@ program
|
|
|
3744
3787
|
|
|
3745
3788
|
Runs scan-soul internally to identify missing controls, then generates
|
|
3746
3789
|
template content for each missing domain. Existing content is preserved.
|
|
3790
|
+
Supports iterative hardening: if a domain heading exists but controls
|
|
3791
|
+
fail within it, appends targeted remediation for those controls.
|
|
3747
3792
|
|
|
3748
3793
|
Modes:
|
|
3749
3794
|
Default: Append missing sections to SOUL.md (or create it)
|
|
@@ -3756,6 +3801,7 @@ Examples:
|
|
|
3756
3801
|
$ hackmyagent harden-soul --json Machine-readable output`)
|
|
3757
3802
|
.argument('[directory]', 'Directory to harden (defaults to current directory)', '.')
|
|
3758
3803
|
.option('--dry-run', 'Preview changes without modifying files')
|
|
3804
|
+
.option('--profile <profile>', 'Override agent profile (conversational, code-assistant, tool-agent, autonomous, orchestrator, custom)')
|
|
3759
3805
|
.option('--json', 'Output as JSON')
|
|
3760
3806
|
.action(async (directory, options) => {
|
|
3761
3807
|
try {
|
|
@@ -3764,8 +3810,9 @@ Examples:
|
|
|
3764
3810
|
process.stderr.write(`Error: Directory '${targetDir}' does not exist.\n`);
|
|
3765
3811
|
process.exit(1);
|
|
3766
3812
|
}
|
|
3813
|
+
const prefix = getCommandPrefix();
|
|
3767
3814
|
const scanner = new index_1.SoulScanner();
|
|
3768
|
-
const result = await scanner.hardenSoul(targetDir, { dryRun: options.dryRun });
|
|
3815
|
+
const result = await scanner.hardenSoul(targetDir, { dryRun: options.dryRun, profile: options.profile });
|
|
3769
3816
|
// JSON output
|
|
3770
3817
|
if (options.json) {
|
|
3771
3818
|
// Exclude full content from JSON to keep it concise
|
|
@@ -3782,7 +3829,7 @@ Examples:
|
|
|
3782
3829
|
// Text output
|
|
3783
3830
|
if (result.sectionsAdded.length === 0) {
|
|
3784
3831
|
process.stdout.write(`\n${colors.green}All governance domains already have sections in ${result.file}.${colors.reset}\n`);
|
|
3785
|
-
process.stdout.write(`Run '
|
|
3832
|
+
process.stdout.write(`Run '${prefix} scan-soul --verbose' to see individual control coverage.\n\n`);
|
|
3786
3833
|
return;
|
|
3787
3834
|
}
|
|
3788
3835
|
if (result.dryRun) {
|
|
@@ -3817,7 +3864,7 @@ Examples:
|
|
|
3817
3864
|
process.stdout.write(` ${colors.green}+${colors.reset} ${section}\n`);
|
|
3818
3865
|
}
|
|
3819
3866
|
process.stdout.write(`Controls covered: +${result.controlsAdded}\n\n`);
|
|
3820
|
-
process.stdout.write(`Run '${colors.cyan}
|
|
3867
|
+
process.stdout.write(`Run '${colors.cyan}${prefix} scan-soul${colors.reset}' to verify coverage.\n\n`);
|
|
3821
3868
|
}
|
|
3822
3869
|
}
|
|
3823
3870
|
catch (error) {
|