@jamaynor/hal-config 1.0.1
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/CLAUDE.md +84 -0
- package/index.js +3 -0
- package/lib/config.js +675 -0
- package/package.json +23 -0
- package/publish.ps1 +30 -0
- package/security/access-control.js +308 -0
- package/security/governor.js +313 -0
- package/security/index.js +31 -0
- package/security/redactor.js +129 -0
- package/security/sanitizer.js +571 -0
- package/test/config-io.test.js +326 -0
- package/test/security.test.js +488 -0
- package/test/test-utils.test.js +360 -0
- package/test/test.js +586 -0
- package/test-utils.js +255 -0
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# CLAUDE.md — @jamaynor/hal-config
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Shared configuration loader for HAL OpenClaw skills. Reads `hal-system-config.json` once, caches for the process lifetime, and provides accessors for shared data and skill discovery.
|
|
6
|
+
|
|
7
|
+
Zero runtime dependencies. ESM (ES modules). Node >= 22.
|
|
8
|
+
|
|
9
|
+
## API
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
import halConfig from '@jamaynor/hal-config';
|
|
13
|
+
|
|
14
|
+
// Loading
|
|
15
|
+
halConfig.load(configDir?) // Read hal-system-config.json (defaults to HAL_SYSTEM_CONFIG env)
|
|
16
|
+
halConfig.reload() // Bust cache and re-read
|
|
17
|
+
halConfig.raw() // Full config object
|
|
18
|
+
halConfig.configDir() // Resolved config directory path
|
|
19
|
+
|
|
20
|
+
// Shared data
|
|
21
|
+
halConfig.vaults() // hal-obsidian-vaults array (raw)
|
|
22
|
+
halConfig.accounts(provider?) // hal-communication-accounts, optionally filtered
|
|
23
|
+
halConfig.timezone() // string or null
|
|
24
|
+
halConfig.workHours() // { start, end } or null
|
|
25
|
+
|
|
26
|
+
// Skill discovery
|
|
27
|
+
halConfig.skill(name) // Full skill config block or null
|
|
28
|
+
halConfig.isEnabled(name) // boolean — exists and enabled !== false
|
|
29
|
+
halConfig.isInstalled(name) // boolean — enabled + binary on PATH (sync)
|
|
30
|
+
halConfig.isInstalledAsync(name) // Promise<boolean> — async version
|
|
31
|
+
halConfig.skillWorkspace(name) // runtime.workspace or null
|
|
32
|
+
halConfig.skillBinaries(name) // string[] of binary names from install metadata
|
|
33
|
+
halConfig.homeAgent(name) // homeAgent string or null (null = primary agent)
|
|
34
|
+
|
|
35
|
+
// Deterministic locations (no searching)
|
|
36
|
+
halConfig.openclawSharedWorkspaceRoot() // /data/openclaw/workspace
|
|
37
|
+
halConfig.openclawConfigFilePath() // /data/openclaw/openclaw.json
|
|
38
|
+
halConfig.halSystemConfigDir() // /data/openclaw/hal (or HAL_SYSTEM_CONFIG)
|
|
39
|
+
halConfig.halSystemConfigFilePath() // {halSystemConfigDir}/hal-system-config.json
|
|
40
|
+
halConfig.halSkillAdminRoot(skillName) // /data/openclaw/hal/{skillName} (or HAL_SKILL_ADMIN_ROOT)
|
|
41
|
+
halConfig.halSkillConfigDir(skillName) // /data/openclaw/hal/{skillName}/config
|
|
42
|
+
halConfig.skillConfigPath(skillName) // /data/openclaw/hal/{skillName}/config/{skillName}.json
|
|
43
|
+
halConfig.skillConfigDir(skillName) // /data/openclaw/hal/{skillName}/config
|
|
44
|
+
halConfig.halSkillLogDir(skillName) // /data/openclaw/hal/{skillName}/log
|
|
45
|
+
|
|
46
|
+
// Per-skill config files (read/write)
|
|
47
|
+
halConfig.halSkillConfig.read(skillNameOrScope) // {} if missing; throws on invalid JSON
|
|
48
|
+
halConfig.halSkillConfig.getSetting(skillNameOrScope, key) // returns value or undefined
|
|
49
|
+
halConfig.halSkillConfig.write(skillNameOrScope, obj) // overwrites entire {skill}.json (atomic)
|
|
50
|
+
halConfig.halSkillConfig.merge(skillNameOrScope, patchObj) // deep merge (objects merge, arrays replace) + write (atomic)
|
|
51
|
+
halConfig.halSkillConfig.setSetting(skillNameOrScope, key, value) // merge single key + write (atomic)
|
|
52
|
+
|
|
53
|
+
// Registration (for init wizards to write back)
|
|
54
|
+
halConfig.register(name, data) // Merge into skills[name].runtime
|
|
55
|
+
halConfig.writeAccounts(accounts) // Merge-by-label upsert into hal-communication-accounts
|
|
56
|
+
halConfig.writeSkillConfig(name, data) // Merge into skills[name]
|
|
57
|
+
halConfig.writeSharedSettings(settings) // Write top-level keys (hal-timezone, etc.)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Config Location
|
|
61
|
+
|
|
62
|
+
Resolved in order: `configDir` argument > `HAL_SYSTEM_CONFIG` env > `/data/openclaw/hal`
|
|
63
|
+
|
|
64
|
+
File: `hal-system-config.json` (v2.0)
|
|
65
|
+
|
|
66
|
+
## Error Handling
|
|
67
|
+
|
|
68
|
+
- Missing file → returns `{}` (graceful). Skills that require the file (email-triage) enforce this at their wrapper level.
|
|
69
|
+
- Corrupt JSON → throws `SyntaxError`
|
|
70
|
+
- Auto-loads on first accessor call if `load()` not called explicitly
|
|
71
|
+
|
|
72
|
+
## Testing
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
npm test
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
147 tests using `node:test`. Tests use temp directories with synthetic configs — no real system-config needed.
|
|
79
|
+
|
|
80
|
+
## How Skills Use It
|
|
81
|
+
|
|
82
|
+
Each skill adds `"hal-config": "file:../hal-config"` to its `package.json` dependencies. When `npm install -g` runs inside the container, npm resolves the `file:` path relative to the skill's source directory (`/repos/jamaynor/<skill>/`).
|
|
83
|
+
|
|
84
|
+
Skills keep thin wrappers in `lib/config/system-config.js` that delegate to this package while preserving their existing function signatures.
|
package/index.js
ADDED