@@ -33,6 +33,7 @@ type PolicyCall = {
3333 sandboxName ?: string ;
3434 presetName ?: string ;
3535 path ?: string ;
36+ presets ?: string [ ] ;
3637} ;
3738
3839type AppliedOptions = {
@@ -63,6 +64,7 @@ function runPolicyAdd(
6364 extraArgs : string [ ] = [ ] ,
6465 envOverrides : Record < string , string | undefined > = { } ,
6566 presetName : string = "pypi" ,
67+ agent : string | null = null ,
6668) {
6769 const tmpDir = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , "nemoclaw-policy-add-" ) ) ;
6870 const scriptPath = path . join ( tmpDir , "policy-add-check.js" ) ;
@@ -71,19 +73,25 @@ const registry = require(${REGISTRY_PATH});
7173const policies = require(${ POLICIES_PATH } );
7274const credentials = require(${ CREDENTIALS_PATH } );
7375const calls = [];
74- policies.selectFromList = async () => ${ JSON . stringify ( presetName ) } ;
76+ policies.selectFromList = async (items) => {
77+ calls.push({ type: "select", presets: items.map((item) => item.name) });
78+ return ${ JSON . stringify ( presetName ) } ;
79+ };
7580policies.loadPreset = () => "network_policies:\n example:\n host: example.com\n";
7681policies.getPresetEndpoints = () => ["example.com"];
7782credentials.prompt = async (message) => {
7883 calls.push({ type: "prompt", message });
7984 return ${ JSON . stringify ( confirmAnswer ) } ;
8085};
81- registry.getSandbox = (name) => (name === "test-sandbox" ? { name } : null);
82- registry.listSandboxes = () => ({ sandboxes: [{ name: "test-sandbox" }] });
86+ registry.getSandbox = (name) => (name === "test-sandbox" ? { name, agent: ${ JSON . stringify ( agent ) } } : null);
87+ registry.listSandboxes = () => ({ sandboxes: [{ name: "test-sandbox", agent: ${ JSON . stringify ( agent ) } }] });
8388policies.listPresets = () => [
8489 { name: "npm", description: "npm and Yarn registry access" },
8590 { name: "pypi", description: "Python Package Index (PyPI) access" },
8691 { name: "discord", description: "Discord API, gateway, and CDN access" },
92+ { name: "openclaw-pricing", description: "OpenClaw pricing lookup" },
93+ { name: "nous-web", description: "Nous Portal managed web search and crawl gateway" },
94+ { name: "nous-code", description: "Nous Portal managed sandboxed code execution gateway" },
8795];
8896policies.getAppliedPresets = () => [];
8997policies.applyPreset = (sandboxName, presetName) => {
@@ -2387,6 +2395,48 @@ selectForRemoval(items, options)
23872395 ) ;
23882396 } ) ;
23892397
2398+ it ( "filters Hermes-only presets from the OpenClaw policy-add picker" , ( ) => {
2399+ const result = runPolicyAdd ( "y" , [ ] , { } , "pypi" , "openclaw" ) ;
2400+
2401+ expect ( result . status ) . toBe ( 0 ) ;
2402+ const calls = JSON . parse ( result . stdout . split ( "__CALLS__" ) [ 1 ] . trim ( ) ) as PolicyCall [ ] ;
2403+ const selectCall = calls . find ( ( call ) => call . type === "select" ) ;
2404+ expect ( selectCall ?. presets ) . toEqual (
2405+ expect . arrayContaining ( [ "npm" , "pypi" , "discord" , "openclaw-pricing" ] ) ,
2406+ ) ;
2407+ expect ( selectCall ?. presets ) . not . toContain ( "nous-web" ) ;
2408+ expect ( selectCall ?. presets ) . not . toContain ( "nous-code" ) ;
2409+ } ) ;
2410+
2411+ it ( "rejects Hermes-only preset names for OpenClaw policy-add" , ( ) => {
2412+ const result = runPolicyAdd ( "y" , [ "nous-web" , "--yes" ] , { } , "pypi" , "openclaw" ) ;
2413+
2414+ expect ( result . status ) . not . toBe ( 0 ) ;
2415+ expect ( result . stderr ) . toMatch ( / U n k n o w n p r e s e t ' n o u s - w e b ' / ) ;
2416+ expect ( result . stderr ) . toMatch ( / V a l i d p r e s e t s : n p m , p y p i , d i s c o r d , o p e n c l a w - p r i c i n g / ) ;
2417+ expect ( result . stderr ) . not . toMatch ( / n o u s - c o d e / ) ;
2418+ } ) ;
2419+
2420+ it ( "filters OpenClaw-only presets from the Hermes policy-add picker" , ( ) => {
2421+ const result = runPolicyAdd ( "y" , [ ] , { } , "pypi" , "hermes" ) ;
2422+
2423+ expect ( result . status ) . toBe ( 0 ) ;
2424+ const calls = JSON . parse ( result . stdout . split ( "__CALLS__" ) [ 1 ] . trim ( ) ) as PolicyCall [ ] ;
2425+ const selectCall = calls . find ( ( call ) => call . type === "select" ) ;
2426+ expect ( selectCall ?. presets ) . toEqual (
2427+ expect . arrayContaining ( [ "npm" , "pypi" , "discord" , "nous-web" , "nous-code" ] ) ,
2428+ ) ;
2429+ expect ( selectCall ?. presets ) . not . toContain ( "openclaw-pricing" ) ;
2430+ } ) ;
2431+
2432+ it ( "rejects OpenClaw-only preset names for Hermes policy-add" , ( ) => {
2433+ const result = runPolicyAdd ( "y" , [ "openclaw-pricing" , "--yes" ] , { } , "pypi" , "hermes" ) ;
2434+
2435+ expect ( result . status ) . not . toBe ( 0 ) ;
2436+ expect ( result . stderr ) . toMatch ( / U n k n o w n p r e s e t ' o p e n c l a w - p r i c i n g ' / ) ;
2437+ expect ( result . stderr ) . toMatch ( / V a l i d p r e s e t s : n p m , p y p i , d i s c o r d , n o u s - w e b , n o u s - c o d e / ) ;
2438+ } ) ;
2439+
23902440 it ( "warns the user that the telegram preset alone does not enable Telegram messaging" , ( ) => {
23912441 const result = runPolicyAdd ( "y" , [ ] , { } , "telegram" ) ;
23922442
0 commit comments