@hmharness/agent 0.7.0 → 0.8.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.
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @hmharness/agent - capability plane (V2 blueprint M4).
3
+ *
4
+ * Projects every registered tool - native, MCP, domain - onto a
5
+ * CapabilityManifest: an auditable declaration of id, risk, permissions,
6
+ * approval requirement and side effects. The PolicyEngine then answers
7
+ * "may this capability run in this mode?" for lockdown/standard modes.
8
+ * This is the DECLARATION layer on top of the existing enforcement layer
9
+ * (kernel needsApproval + shellgate + DENY_PATTERNS stay authoritative);
10
+ * manifests make the security surface inspectable (`hmh capability list`).
11
+ */
12
+ import type { Tool } from '@hmharness/kernel';
13
+ export type CapabilityRisk = 'low' | 'medium' | 'high' | 'critical';
14
+ export interface CapabilityManifest {
15
+ id: string;
16
+ version: string;
17
+ description: string;
18
+ risk: CapabilityRisk;
19
+ /** coarse permission buckets derived from the tool's nature */
20
+ permissions: string[];
21
+ requiresApproval: boolean;
22
+ network: boolean;
23
+ sideEffects: string[];
24
+ }
25
+ export declare function manifestFor(tool: Tool): CapabilityManifest;
26
+ export declare function capabilityReport(registry: {
27
+ list(): Tool[];
28
+ }): CapabilityManifest[];
29
+ export type PolicyMode = 'standard' | 'lockdown';
30
+ export interface PolicyDecision {
31
+ allow: boolean;
32
+ reason: string;
33
+ }
34
+ /** Lockdown mode: anything with host/device/process reach is denied outright;
35
+ * approval-gated capabilities still require their gate. Standard mode:
36
+ * mirrors the existing enforcement (declaration-only view). */
37
+ export declare function authorize(manifest: CapabilityManifest, mode: PolicyMode, deniedIds?: ReadonlySet<string>): PolicyDecision;
@@ -0,0 +1,43 @@
1
+ /** Tool-name heuristics -> permission buckets and risk. Declaration only -
2
+ * enforcement stays in kernel (needsApproval/shellgate/DENY_PATTERNS). */
3
+ const RISK_RULES = [
4
+ { match: /^(run_command|ssh_run)$/, risk: 'high', permissions: ['process.spawn', 'fs.read', 'fs.write', 'net.remote'], network: true, sideEffects: ['host-process', 'remote-exec'] },
5
+ { match: /^(write_file|edit_file)$/, risk: 'medium', permissions: ['fs.write'], network: false, sideEffects: ['file-mutation'] },
6
+ { match: /^desktop_(click|type)$/, risk: 'high', permissions: ['desktop.control'], network: false, sideEffects: ['host-ui-input'] },
7
+ { match: /^desktop_screenshot$/, risk: 'medium', permissions: ['desktop.read'], network: false, sideEffects: [] },
8
+ { match: /^(browser_open|web_search|web_fetch)$/, risk: 'low', permissions: ['net.egress'], network: true, sideEffects: [] },
9
+ { match: /^(harmony_install|harmony_launch|harmony_uninstall|harmony_sign)$/, risk: 'high', permissions: ['device.write'], network: false, sideEffects: ['device-mutation'] },
10
+ { match: /^(harmony_emulator_(create|start|stop|delete))$/, risk: 'high', permissions: ['device.write', 'process.spawn'], network: true, sideEffects: ['device-mutation'] },
11
+ { match: /^(harmony_build|harmony_cjpm_build|harmony_cjpm_test|harmony_lint)$/, risk: 'medium', permissions: ['process.spawn', 'fs.write'], network: true, sideEffects: ['build-artifacts'] },
12
+ { match: /^spawn_agent$/, risk: 'high', permissions: ['agent.spawn'], network: false, sideEffects: ['subagent-run'] },
13
+ ];
14
+ export function manifestFor(tool) {
15
+ const rule = RISK_RULES.find((r) => r.match.test(tool.name));
16
+ const requiresApproval = typeof tool.needsApproval === 'function';
17
+ return {
18
+ id: tool.name,
19
+ version: '1.0.0',
20
+ description: tool.description.split('\n')[0].slice(0, 160),
21
+ risk: rule?.risk ?? (requiresApproval ? 'medium' : 'low'),
22
+ permissions: rule?.permissions ?? (requiresApproval ? ['gated.unknown'] : ['fs.read']),
23
+ requiresApproval,
24
+ network: rule?.network ?? false,
25
+ sideEffects: rule?.sideEffects ?? [],
26
+ };
27
+ }
28
+ export function capabilityReport(registry) {
29
+ return registry.list().map(manifestFor).sort((a, b) => a.id.localeCompare(b.id));
30
+ }
31
+ /** Lockdown mode: anything with host/device/process reach is denied outright;
32
+ * approval-gated capabilities still require their gate. Standard mode:
33
+ * mirrors the existing enforcement (declaration-only view). */
34
+ export function authorize(manifest, mode, deniedIds = new Set()) {
35
+ if (deniedIds.has(manifest.id))
36
+ return { allow: false, reason: `capability revoked: ${manifest.id}` };
37
+ if (mode === 'lockdown') {
38
+ const dangerous = manifest.permissions.some((p) => p.startsWith('process.') || p.startsWith('device.write') || p.startsWith('desktop.control') || p.startsWith('net.remote') || p.startsWith('agent.'));
39
+ if (dangerous)
40
+ return { allow: false, reason: `lockdown: ${manifest.id} touches ${manifest.permissions.filter((p) => !p.startsWith('fs.')).join(', ')}` };
41
+ }
42
+ return { allow: true, reason: manifest.requiresApproval ? 'allowed, approval gate applies' : 'allowed' };
43
+ }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { baseTools, readFileTool, writeFileTool, listDirTool, runCommandTool, rememberTool, seeImageTool } from './tools.ts';
2
+ export { manifestFor, capabilityReport, authorize, type CapabilityManifest, type CapabilityRisk, type PolicyMode } from './capability.ts';
2
3
  export { buildSystemPrompt } from './prompt.ts';
3
4
  export { strings, type Locale, type Strings } from './i18n.ts';
4
5
  export { makeSpawnTool, MAX_SPAWN_DEPTH, type SpawnBase } from './spawn.ts';
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { baseTools, readFileTool, writeFileTool, listDirTool, runCommandTool, rememberTool, seeImageTool } from "./tools.js";
2
+ export { manifestFor, capabilityReport, authorize } from "./capability.js";
2
3
  export { buildSystemPrompt } from "./prompt.js";
3
4
  export { strings } from "./i18n.js";
4
5
  export { makeSpawnTool, MAX_SPAWN_DEPTH } from "./spawn.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hmharness/agent",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "hmharness agent execution layer: base tools, system prompt, sub-agent spawn, and the shared task runner that frontends (cli, web) drive.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -15,11 +15,11 @@
15
15
  "build": "tsc -p tsconfig.build.json"
16
16
  },
17
17
  "dependencies": {
18
- "@hmharness/kernel": "0.7.0",
18
+ "@hmharness/kernel": "0.8.0",
19
19
  "@hmharness/observability": "0.7.0",
20
- "@hmharness/evolution": "0.7.0",
21
- "@hmharness/domain-harmony": "0.7.0",
22
- "@hmharness/domain-ops": "0.7.0"
20
+ "@hmharness/evolution": "0.8.0",
21
+ "@hmharness/domain-harmony": "0.8.0",
22
+ "@hmharness/domain-ops": "0.8.0"
23
23
  },
24
24
  "files": [
25
25
  "dist"