@vectorize-io/hindsight-nemoclaw 0.1.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/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # hindsight-nemoclaw
2
+
3
+ One-command setup for [Hindsight](https://hindsight.vectorize.io) persistent memory on [NemoClaw](https://nemoclaw.ai) sandboxes.
4
+
5
+ NemoClaw runs [OpenClaw](https://openclaw.ai) inside an OpenShell sandbox with strict network egress policies. This package automates the full setup: installing the `hindsight-openclaw` plugin, configuring external API mode, merging the Hindsight egress rule into your sandbox policy, and restarting the gateway.
6
+
7
+ ## Quick Start
8
+
9
+ ```bash
10
+ npx @vectorize-io/hindsight-nemoclaw setup \
11
+ --sandbox my-assistant \
12
+ --api-url https://api.hindsight.vectorize.io \
13
+ --api-token <your-api-key> \
14
+ --bank-prefix my-sandbox
15
+ ```
16
+
17
+ Get an API key at [Hindsight Cloud](https://ui.hindsight.vectorize.io/signup).
18
+
19
+ ## Documentation
20
+
21
+ Full setup guide, pitfalls, and troubleshooting:
22
+
23
+ **[NemoClaw Integration Documentation](https://vectorize.io/hindsight/sdks/integrations/nemoclaw)**
24
+
25
+ Or see [NEMOCLAW.md](./NEMOCLAW.md) in this directory for a step-by-step walkthrough.
26
+
27
+ ## CLI Reference
28
+
29
+ ```
30
+ hindsight-nemoclaw setup [options]
31
+
32
+ Options:
33
+ --sandbox <name> NemoClaw sandbox name (required)
34
+ --api-url <url> Hindsight API URL (required)
35
+ --api-token <token> Hindsight API token (required)
36
+ --bank-prefix <prefix> Memory bank prefix (default: "nemoclaw")
37
+ --skip-policy Skip sandbox network policy update
38
+ --skip-plugin-install Skip openclaw plugin installation
39
+ --dry-run Preview changes without applying
40
+ --help Show help
41
+ ```
42
+
43
+ ## What It Does
44
+
45
+ 1. **Preflight** — verifies `openshell` and `openclaw` are installed
46
+ 2. **Install plugin** — runs `openclaw plugins install @vectorize-io/hindsight-openclaw`
47
+ 3. **Configure plugin** — writes external API mode config to `~/.openclaw/openclaw.json`
48
+ 4. **Apply policy** — reads current sandbox policy, merges Hindsight egress rule, re-applies via `openshell policy set`
49
+ 5. **Restart gateway** — runs `openclaw gateway restart`
50
+
51
+ ## Links
52
+
53
+ - [Hindsight Documentation](https://vectorize.io/hindsight)
54
+ - [NemoClaw](https://nemoclaw.ai)
55
+ - [OpenClaw](https://openclaw.ai)
56
+ - [GitHub Repository](https://github.com/vectorize-io/hindsight)
57
+
58
+ ## License
59
+
60
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env node
2
+ import { runSetup } from './setup.js';
3
+ function usage() {
4
+ process.stdout.write(`
5
+ hindsight-nemoclaw — Setup CLI for Hindsight memory on NemoClaw sandboxes
6
+
7
+ Usage:
8
+ hindsight-nemoclaw setup [options]
9
+
10
+ Required options:
11
+ --sandbox <name> NemoClaw sandbox name (e.g. my-assistant)
12
+ --api-url <url> Hindsight Cloud API URL (https://api.hindsight.vectorize.io)
13
+ --api-token <token> Hindsight API key from https://ui.hindsight.vectorize.io
14
+ --bank-prefix <prefix> Bank ID prefix (memories go to <prefix>-openclaw)
15
+
16
+ Optional options:
17
+ --skip-policy Skip the openshell policy update
18
+ --skip-plugin-install Skip openclaw plugins install
19
+ --dry-run Print what would be changed without executing
20
+ --help Show this help
21
+
22
+ Example:
23
+ hindsight-nemoclaw setup \\
24
+ --sandbox my-assistant \\
25
+ --api-url https://api.hindsight.vectorize.io \\
26
+ --api-token hsk_abc123 \\
27
+ --bank-prefix my-sandbox
28
+ `);
29
+ }
30
+ function parseArgs(argv) {
31
+ const args = argv.slice(2);
32
+ if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
33
+ usage();
34
+ return null;
35
+ }
36
+ if (args[0] !== 'setup') {
37
+ process.stderr.write(`Unknown command: ${args[0]}\nRun with --help for usage.\n`);
38
+ process.exit(1);
39
+ }
40
+ const get = (flag) => {
41
+ const idx = args.indexOf(flag);
42
+ if (idx === -1 || idx + 1 >= args.length)
43
+ return undefined;
44
+ return args[idx + 1];
45
+ };
46
+ const sandbox = get('--sandbox');
47
+ const apiUrl = get('--api-url');
48
+ const apiToken = get('--api-token');
49
+ const bankPrefix = get('--bank-prefix');
50
+ const missing = [];
51
+ if (!sandbox)
52
+ missing.push('--sandbox');
53
+ if (!apiUrl)
54
+ missing.push('--api-url');
55
+ if (!apiToken)
56
+ missing.push('--api-token');
57
+ if (!bankPrefix)
58
+ missing.push('--bank-prefix');
59
+ if (missing.length > 0) {
60
+ process.stderr.write(`Missing required options: ${missing.join(', ')}\nRun with --help for usage.\n`);
61
+ process.exit(1);
62
+ }
63
+ return {
64
+ sandbox: sandbox,
65
+ apiUrl: apiUrl,
66
+ apiToken: apiToken,
67
+ bankPrefix: bankPrefix,
68
+ skipPolicy: args.includes('--skip-policy'),
69
+ skipPluginInstall: args.includes('--skip-plugin-install'),
70
+ dryRun: args.includes('--dry-run'),
71
+ };
72
+ }
73
+ const args = parseArgs(process.argv);
74
+ if (args) {
75
+ runSetup(args).catch(err => {
76
+ process.stderr.write(`\nError: ${err instanceof Error ? err.message : String(err)}\n`);
77
+ process.exit(1);
78
+ });
79
+ }
@@ -0,0 +1,27 @@
1
+ import { dirname } from 'path';
2
+ declare const CONFIG_PATH: string;
3
+ export interface HindsightPluginConfig {
4
+ hindsightApiUrl: string;
5
+ hindsightApiToken: string;
6
+ llmProvider: string;
7
+ dynamicBankId: boolean;
8
+ bankIdPrefix: string;
9
+ }
10
+ export interface OpenClawConfig {
11
+ plugins?: {
12
+ slots?: Record<string, string>;
13
+ entries?: Record<string, {
14
+ enabled: boolean;
15
+ config?: Record<string, unknown>;
16
+ }>;
17
+ installs?: Record<string, unknown>;
18
+ [key: string]: unknown;
19
+ };
20
+ [key: string]: unknown;
21
+ }
22
+ export declare function readOpenClawConfig(configPath?: string): Promise<OpenClawConfig>;
23
+ export declare function mergePluginConfig(config: OpenClawConfig, pluginConfig: HindsightPluginConfig): OpenClawConfig;
24
+ export declare function writeOpenClawConfig(config: OpenClawConfig, configPath?: string): Promise<void>;
25
+ export declare function applyPluginConfig(pluginConfig: HindsightPluginConfig, configPath?: string): Promise<void>;
26
+ export { CONFIG_PATH };
27
+ export { dirname };
@@ -0,0 +1,71 @@
1
+ import { readFile, writeFile, rename } from 'fs/promises';
2
+ import { join, dirname } from 'path';
3
+ import { homedir } from 'os';
4
+ import { randomBytes } from 'crypto';
5
+ const CONFIG_PATH = join(homedir(), '.openclaw', 'openclaw.json');
6
+ export async function readOpenClawConfig(configPath = CONFIG_PATH) {
7
+ let raw;
8
+ try {
9
+ raw = await readFile(configPath, 'utf8');
10
+ }
11
+ catch (err) {
12
+ const code = err.code;
13
+ if (code === 'ENOENT') {
14
+ throw new Error(`OpenClaw config not found at ${configPath}.\n` +
15
+ `Run \`openclaw\` once to initialize it, then re-run setup.`);
16
+ }
17
+ throw err;
18
+ }
19
+ return JSON.parse(raw);
20
+ }
21
+ export function mergePluginConfig(config, pluginConfig) {
22
+ const plugins = config.plugins ?? {};
23
+ const entries = plugins.entries ?? {};
24
+ const existing = entries['hindsight-openclaw'] ?? { enabled: true };
25
+ return {
26
+ ...config,
27
+ plugins: {
28
+ ...plugins,
29
+ slots: {
30
+ ...(plugins.slots ?? {}),
31
+ memory: 'hindsight-openclaw',
32
+ },
33
+ entries: {
34
+ ...entries,
35
+ 'hindsight-openclaw': {
36
+ ...existing,
37
+ enabled: true,
38
+ config: {
39
+ ...(existing.config ?? {}),
40
+ hindsightApiUrl: pluginConfig.hindsightApiUrl,
41
+ hindsightApiToken: pluginConfig.hindsightApiToken,
42
+ llmProvider: pluginConfig.llmProvider,
43
+ dynamicBankId: pluginConfig.dynamicBankId,
44
+ bankIdPrefix: pluginConfig.bankIdPrefix,
45
+ },
46
+ },
47
+ },
48
+ installs: {
49
+ ...(plugins.installs ?? {}),
50
+ 'hindsight-openclaw': {
51
+ source: 'npm',
52
+ version: 'latest',
53
+ installedAt: new Date().toISOString(),
54
+ },
55
+ },
56
+ },
57
+ };
58
+ }
59
+ export async function writeOpenClawConfig(config, configPath = CONFIG_PATH) {
60
+ const contents = JSON.stringify(config, null, 2) + '\n';
61
+ const tmp = `${configPath}.${randomBytes(6).toString('hex')}.tmp`;
62
+ await writeFile(tmp, contents, 'utf8');
63
+ await rename(tmp, configPath);
64
+ }
65
+ export async function applyPluginConfig(pluginConfig, configPath = CONFIG_PATH) {
66
+ const current = await readOpenClawConfig(configPath);
67
+ const updated = mergePluginConfig(current, pluginConfig);
68
+ await writeOpenClawConfig(updated, configPath);
69
+ }
70
+ export { CONFIG_PATH };
71
+ export { dirname };
@@ -0,0 +1,26 @@
1
+ import type { SandboxPolicy } from './types.js';
2
+ /** Strip ANSI escape codes from a string */
3
+ export declare function stripAnsi(str: string): string;
4
+ /**
5
+ * Extract and dedent the policy section from `openshell sandbox get` output.
6
+ * The output looks like:
7
+ *
8
+ * Sandbox:
9
+ * Id: ...
10
+ * Name: ...
11
+ *
12
+ * Policy:
13
+ * version: 1
14
+ * filesystem_policy:
15
+ * ...
16
+ *
17
+ * We need to extract everything after `Policy:` and dedent by 2 spaces.
18
+ */
19
+ export declare function extractPolicyYaml(raw: string): string;
20
+ /**
21
+ * Parse `openshell sandbox get <name>` output into a SandboxPolicy object.
22
+ * Throws a descriptive error if parsing fails.
23
+ */
24
+ export declare function parseSandboxPolicy(rawOutput: string): SandboxPolicy;
25
+ /** Run `openshell sandbox get <sandbox>` and return parsed policy */
26
+ export declare function readSandboxPolicy(sandboxName: string): Promise<SandboxPolicy>;
@@ -0,0 +1,76 @@
1
+ import { execFile } from 'child_process';
2
+ import { promisify } from 'util';
3
+ import yaml from 'js-yaml';
4
+ const execFileAsync = promisify(execFile);
5
+ /** Strip ANSI escape codes from a string */
6
+ export function stripAnsi(str) {
7
+ return str.replace(/\x1B\[[0-9;]*m/g, '');
8
+ }
9
+ /**
10
+ * Extract and dedent the policy section from `openshell sandbox get` output.
11
+ * The output looks like:
12
+ *
13
+ * Sandbox:
14
+ * Id: ...
15
+ * Name: ...
16
+ *
17
+ * Policy:
18
+ * version: 1
19
+ * filesystem_policy:
20
+ * ...
21
+ *
22
+ * We need to extract everything after `Policy:` and dedent by 2 spaces.
23
+ */
24
+ export function extractPolicyYaml(raw) {
25
+ const stripped = stripAnsi(raw);
26
+ const lines = stripped.split('\n');
27
+ const policyHeaderIdx = lines.findIndex(l => l.trimEnd() === 'Policy:');
28
+ if (policyHeaderIdx === -1) {
29
+ throw new Error('Could not find "Policy:" section in `openshell sandbox get` output');
30
+ }
31
+ const policyLines = lines.slice(policyHeaderIdx + 1);
32
+ // Dedent by 2 spaces (the policy block is indented under `Policy:`)
33
+ const dedented = policyLines.map(l => {
34
+ if (l.startsWith(' '))
35
+ return l.slice(2);
36
+ return l;
37
+ });
38
+ // Drop trailing empty lines
39
+ while (dedented.length > 0 && dedented[dedented.length - 1].trim() === '') {
40
+ dedented.pop();
41
+ }
42
+ return dedented.join('\n');
43
+ }
44
+ /**
45
+ * Parse `openshell sandbox get <name>` output into a SandboxPolicy object.
46
+ * Throws a descriptive error if parsing fails.
47
+ */
48
+ export function parseSandboxPolicy(rawOutput) {
49
+ const policyYaml = extractPolicyYaml(rawOutput);
50
+ try {
51
+ const parsed = yaml.load(policyYaml);
52
+ if (typeof parsed !== 'object' || parsed === null) {
53
+ throw new Error('Parsed policy is not an object');
54
+ }
55
+ return parsed;
56
+ }
57
+ catch (err) {
58
+ throw new Error(`Failed to parse sandbox policy YAML.\n` +
59
+ `This may mean the openshell output format has changed.\n` +
60
+ `Apply the Hindsight policy manually using the instructions in NEMOCLAW.md.\n` +
61
+ `Parse error: ${err}`);
62
+ }
63
+ }
64
+ /** Run `openshell sandbox get <sandbox>` and return parsed policy */
65
+ export async function readSandboxPolicy(sandboxName) {
66
+ let stdout;
67
+ try {
68
+ const result = await execFileAsync('openshell', ['sandbox', 'get', sandboxName]);
69
+ stdout = result.stdout;
70
+ }
71
+ catch (err) {
72
+ const msg = err instanceof Error ? err.message : String(err);
73
+ throw new Error(`Failed to run \`openshell sandbox get ${sandboxName}\`: ${msg}`);
74
+ }
75
+ return parseSandboxPolicy(stdout);
76
+ }
@@ -0,0 +1,14 @@
1
+ import type { SandboxPolicy } from './types.js';
2
+ /**
3
+ * Returns true if the policy already has a correct Hindsight network policy entry.
4
+ */
5
+ export declare function hasHindsightPolicy(policy: SandboxPolicy): boolean;
6
+ /**
7
+ * Merge the Hindsight network policy block into a SandboxPolicy.
8
+ * Idempotent — if the block already exists and is correct, returns policy unchanged.
9
+ */
10
+ export declare function mergeHindsightPolicy(policy: SandboxPolicy): SandboxPolicy;
11
+ /**
12
+ * Serialize a SandboxPolicy to a YAML string suitable for `openshell policy set`.
13
+ */
14
+ export declare function serializePolicy(policy: SandboxPolicy): string;
@@ -0,0 +1,55 @@
1
+ import yaml from 'js-yaml';
2
+ import { HINDSIGHT_POLICY_NAME, HINDSIGHT_HOST, OPENCLAW_BINARY } from './types.js';
3
+ const HINDSIGHT_NETWORK_POLICY = {
4
+ name: HINDSIGHT_POLICY_NAME,
5
+ endpoints: [
6
+ {
7
+ host: HINDSIGHT_HOST,
8
+ port: 443,
9
+ protocol: 'rest',
10
+ tls: 'terminate',
11
+ enforcement: 'enforce',
12
+ rules: [
13
+ { allow: { method: 'GET', path: '/**' } },
14
+ { allow: { method: 'POST', path: '/**' } },
15
+ { allow: { method: 'PUT', path: '/**' } },
16
+ ],
17
+ },
18
+ ],
19
+ binaries: [{ path: OPENCLAW_BINARY }],
20
+ };
21
+ /**
22
+ * Returns true if the policy already has a correct Hindsight network policy entry.
23
+ */
24
+ export function hasHindsightPolicy(policy) {
25
+ const np = policy.network_policies?.[HINDSIGHT_POLICY_NAME];
26
+ if (!np)
27
+ return false;
28
+ return np.endpoints?.some(e => e.host === HINDSIGHT_HOST) ?? false;
29
+ }
30
+ /**
31
+ * Merge the Hindsight network policy block into a SandboxPolicy.
32
+ * Idempotent — if the block already exists and is correct, returns policy unchanged.
33
+ */
34
+ export function mergeHindsightPolicy(policy) {
35
+ const updated = {
36
+ ...policy,
37
+ network_policies: {
38
+ ...(policy.network_policies ?? {}),
39
+ [HINDSIGHT_POLICY_NAME]: HINDSIGHT_NETWORK_POLICY,
40
+ },
41
+ };
42
+ return updated;
43
+ }
44
+ /**
45
+ * Serialize a SandboxPolicy to a YAML string suitable for `openshell policy set`.
46
+ */
47
+ export function serializePolicy(policy) {
48
+ return yaml.dump(policy, {
49
+ indent: 2,
50
+ lineWidth: -1,
51
+ noRefs: true,
52
+ quotingType: '"',
53
+ forceQuotes: false,
54
+ });
55
+ }
@@ -0,0 +1,2 @@
1
+ import type { CliArgs } from './types.js';
2
+ export declare function runSetup(args: CliArgs): Promise<void>;
package/dist/setup.js ADDED
@@ -0,0 +1,142 @@
1
+ import { execFile } from 'child_process';
2
+ import { promisify } from 'util';
3
+ import { writeFile, rm } from 'fs/promises';
4
+ import { tmpdir } from 'os';
5
+ import { join } from 'path';
6
+ import { randomBytes } from 'crypto';
7
+ import { readSandboxPolicy } from './policy-reader.js';
8
+ import { hasHindsightPolicy, mergeHindsightPolicy, serializePolicy } from './policy-writer.js';
9
+ import { applyPluginConfig } from './openclaw-config.js';
10
+ const execFileAsync = promisify(execFile);
11
+ function log(msg) {
12
+ process.stdout.write(`${msg}\n`);
13
+ }
14
+ function step(n, msg) {
15
+ log(`\n[${n}] ${msg}`);
16
+ }
17
+ async function which(bin) {
18
+ try {
19
+ await execFileAsync('which', [bin]);
20
+ return true;
21
+ }
22
+ catch {
23
+ return false;
24
+ }
25
+ }
26
+ export async function runSetup(args) {
27
+ log('\nhindsight-nemoclaw setup');
28
+ log('─'.repeat(40));
29
+ // Step 0 — Preflight
30
+ step(0, 'Preflight checks...');
31
+ const [hasOpenshell, hasOpenclaw] = await Promise.all([which('openshell'), which('openclaw')]);
32
+ if (!hasOpenshell) {
33
+ throw new Error('`openshell` not found on PATH. Install it from https://openshell.ai');
34
+ }
35
+ if (!hasOpenclaw) {
36
+ throw new Error('`openclaw` not found on PATH. Install it from https://openclaw.ai');
37
+ }
38
+ log(' ✓ openshell found');
39
+ log(' ✓ openclaw found');
40
+ // Step 1 — Install hindsight-openclaw plugin
41
+ if (!args.skipPluginInstall) {
42
+ step(1, 'Installing @vectorize-io/hindsight-openclaw plugin...');
43
+ if (args.dryRun) {
44
+ log(' [dry-run] would run: openclaw plugins install @vectorize-io/hindsight-openclaw');
45
+ }
46
+ else {
47
+ const { stdout } = await execFileAsync('openclaw', [
48
+ 'plugins', 'install', '@vectorize-io/hindsight-openclaw',
49
+ ]);
50
+ log(stdout.trim() || ' ✓ Plugin installed');
51
+ }
52
+ }
53
+ else {
54
+ step(1, 'Skipping plugin install (--skip-plugin-install)');
55
+ }
56
+ // Step 2 — Configure ~/.openclaw/openclaw.json
57
+ step(2, 'Configuring plugin in ~/.openclaw/openclaw.json...');
58
+ const pluginConfig = {
59
+ hindsightApiUrl: args.apiUrl,
60
+ hindsightApiToken: args.apiToken,
61
+ llmProvider: 'claude-code',
62
+ dynamicBankId: false,
63
+ bankIdPrefix: args.bankPrefix,
64
+ };
65
+ if (args.dryRun) {
66
+ log(` [dry-run] would write plugin config to ~/.openclaw/openclaw.json`);
67
+ log(` config: ${JSON.stringify(pluginConfig, null, 4).split('\n').join('\n ')}`);
68
+ }
69
+ else {
70
+ await applyPluginConfig(pluginConfig);
71
+ log(` ✓ Plugin config written (bank: ${args.bankPrefix}-openclaw)`);
72
+ }
73
+ // Step 3 — Apply OpenShell network policy
74
+ if (!args.skipPolicy) {
75
+ step(3, `Applying Hindsight network policy to sandbox "${args.sandbox}"...`);
76
+ const currentPolicy = await readSandboxPolicy(args.sandbox);
77
+ if (hasHindsightPolicy(currentPolicy)) {
78
+ log(' ✓ Hindsight policy already present — skipping');
79
+ }
80
+ else {
81
+ const updatedPolicy = mergeHindsightPolicy(currentPolicy);
82
+ const policyYaml = serializePolicy(updatedPolicy);
83
+ if (args.dryRun) {
84
+ log(' [dry-run] would apply policy:');
85
+ log(policyYaml.split('\n').map(l => ` ${l}`).join('\n'));
86
+ }
87
+ else {
88
+ const tmpFile = join(tmpdir(), `hindsight-policy-${randomBytes(6).toString('hex')}.yaml`);
89
+ try {
90
+ await writeFile(tmpFile, policyYaml, 'utf8');
91
+ const { stdout } = await execFileAsync('openshell', [
92
+ 'policy', 'set', args.sandbox, '--policy', tmpFile, '--wait',
93
+ ]);
94
+ log(stdout.trim() || ` ✓ Policy applied to sandbox "${args.sandbox}"`);
95
+ }
96
+ finally {
97
+ await rm(tmpFile, { force: true });
98
+ }
99
+ }
100
+ }
101
+ }
102
+ else {
103
+ step(3, 'Skipping policy update (--skip-policy)');
104
+ log(' Add the following block to your sandbox network_policies manually:');
105
+ log('');
106
+ log(' hindsight:');
107
+ log(' name: hindsight');
108
+ log(' endpoints:');
109
+ log(' - host: api.hindsight.vectorize.io');
110
+ log(' port: 443');
111
+ log(' protocol: rest');
112
+ log(' tls: terminate');
113
+ log(' enforcement: enforce');
114
+ log(' rules:');
115
+ log(' - allow: { method: GET, path: /** }');
116
+ log(' - allow: { method: POST, path: /** }');
117
+ log(' - allow: { method: PUT, path: /** }');
118
+ log(' binaries:');
119
+ log(' - path: /usr/local/bin/openclaw');
120
+ }
121
+ // Step 4 — Restart gateway
122
+ step(4, 'Restarting OpenClaw gateway...');
123
+ if (args.dryRun) {
124
+ log(' [dry-run] would run: openclaw gateway restart');
125
+ }
126
+ else {
127
+ await execFileAsync('openclaw', ['gateway', 'restart']);
128
+ log(' ✓ Gateway restarted');
129
+ }
130
+ log('\n' + '─'.repeat(40));
131
+ log('✓ Setup complete!\n');
132
+ log(` Bank ID: ${args.bankPrefix}-openclaw`);
133
+ log(` API URL: ${args.apiUrl}`);
134
+ log('');
135
+ log(' Watch gateway logs to confirm:');
136
+ log(' grep Hindsight ~/.openclaw/logs/gateway.log | tail -5');
137
+ log(' Expected: [Hindsight] ✓ Ready (external API mode)');
138
+ log('');
139
+ log(' Test memory retention:');
140
+ log(` openclaw agent --agent main --session-id test-1 -m "My name is Ben."`);
141
+ log(` openclaw agent --agent main --session-id test-2 -m "What do you remember about me?"`);
142
+ }
@@ -0,0 +1,54 @@
1
+ export interface CliArgs {
2
+ sandbox: string;
3
+ apiUrl: string;
4
+ apiToken: string;
5
+ bankPrefix: string;
6
+ skipPolicy: boolean;
7
+ skipPluginInstall: boolean;
8
+ dryRun: boolean;
9
+ }
10
+ export interface PolicyEndpointRule {
11
+ allow: {
12
+ method: string;
13
+ path: string;
14
+ };
15
+ }
16
+ export interface PolicyEndpoint {
17
+ host: string;
18
+ port: number;
19
+ protocol?: string;
20
+ tls?: string;
21
+ enforcement?: string;
22
+ access?: string;
23
+ rules?: PolicyEndpointRule[];
24
+ }
25
+ export interface PolicyBinary {
26
+ path: string;
27
+ }
28
+ export interface NetworkPolicy {
29
+ name: string;
30
+ endpoints: PolicyEndpoint[];
31
+ binaries?: PolicyBinary[];
32
+ }
33
+ export interface FilesystemPolicy {
34
+ include_workdir?: boolean;
35
+ read_only?: string[];
36
+ read_write?: string[];
37
+ }
38
+ export interface Landlock {
39
+ compatibility?: string;
40
+ }
41
+ export interface ProcessPolicy {
42
+ run_as_user?: string;
43
+ run_as_group?: string;
44
+ }
45
+ export interface SandboxPolicy {
46
+ version?: number;
47
+ filesystem_policy?: FilesystemPolicy;
48
+ landlock?: Landlock;
49
+ process?: ProcessPolicy;
50
+ network_policies?: Record<string, NetworkPolicy>;
51
+ }
52
+ export declare const HINDSIGHT_POLICY_NAME = "hindsight";
53
+ export declare const HINDSIGHT_HOST = "api.hindsight.vectorize.io";
54
+ export declare const OPENCLAW_BINARY = "/usr/local/bin/openclaw";
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ export const HINDSIGHT_POLICY_NAME = 'hindsight';
2
+ export const HINDSIGHT_HOST = 'api.hindsight.vectorize.io';
3
+ export const OPENCLAW_BINARY = '/usr/local/bin/openclaw';
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@vectorize-io/hindsight-nemoclaw",
3
+ "version": "0.1.1",
4
+ "description": "Setup CLI for hindsight-openclaw on NemoClaw sandboxes — installs the plugin, configures external API mode, and applies the OpenShell network policy",
5
+ "type": "module",
6
+ "main": "dist/cli.js",
7
+ "bin": {
8
+ "hindsight-nemoclaw": "dist/cli.js"
9
+ },
10
+ "keywords": [
11
+ "nemoclaw",
12
+ "openclaw",
13
+ "memory",
14
+ "ai",
15
+ "agent",
16
+ "hindsight",
17
+ "openshell",
18
+ "nvidia"
19
+ ],
20
+ "author": "Vectorize <support@vectorize.io>",
21
+ "license": "MIT",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/vectorize-io/hindsight.git",
25
+ "directory": "hindsight-integrations/nemoclaw"
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "README.md"
30
+ ],
31
+ "scripts": {
32
+ "build": "tsc && node -e \"const f='dist/cli.js',s=require('fs');s.writeFileSync(f,'#!/usr/bin/env node\\n'+s.readFileSync(f,'utf8'));s.chmodSync(f,0o755)\"",
33
+ "dev": "tsc --watch",
34
+ "clean": "rm -rf dist",
35
+ "test": "vitest run src",
36
+ "test:watch": "vitest src",
37
+ "prepublishOnly": "npm run clean && npm run build"
38
+ },
39
+ "dependencies": {
40
+ "js-yaml": "^4.1.0"
41
+ },
42
+ "devDependencies": {
43
+ "@types/js-yaml": "^4.0.9",
44
+ "@types/node": "^20.0.0",
45
+ "typescript": "^5.3.0",
46
+ "vitest": "^4.0.18"
47
+ },
48
+ "engines": {
49
+ "node": ">=22"
50
+ }
51
+ }