bare-agent 0.12.0 → 0.12.2

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,84 @@
1
+ #!/usr/bin/env bash
2
+ # examples/wake.sh — reference scheduler for bareagent's defer queue.
3
+ #
4
+ # This is a *reference*, not a primitive. Copy into your project and modify.
5
+ # See examples/wake.md for the cron entry and customization points.
6
+ #
7
+ # What this script does:
8
+ # 1. Reads the JSONL defer queue file.
9
+ # 2. Folds status-update lines per id (latest wins) using jq.
10
+ # 3. For each pending record whose `when` <= now: appends a "fired" status
11
+ # line to the queue (atomic JSONL append), then invokes
12
+ # `bareagent --config <orchestrator>` with the inner action as stdin.
13
+ # 4. Uses flock(1) to prevent overlapping wake invocations.
14
+ #
15
+ # The fired action goes through bareguard's gate AGAIN at fire time — full
16
+ # pipeline against the inner action, separate from the emit-time check.
17
+ # (Two gate.check calls, two distinct audit lines, reconstructable via
18
+ # parent_run_id.)
19
+
20
+ set -euo pipefail
21
+
22
+ QUEUE="${BAREAGENT_DEFER_QUEUE:-./bareagent-defers.jsonl}"
23
+ ORCHESTRATOR_CONFIG="${ORCHESTRATOR_CONFIG:-./orchestrator.json}"
24
+ LOCKFILE="${LOCKFILE:-/tmp/bareagent-wake.lock}"
25
+ LOG_DIR="${BAREAGENT_WAKE_LOG_DIR:-/tmp/bareagent-wake}"
26
+
27
+ mkdir -p "$LOG_DIR"
28
+
29
+ NOW=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
30
+
31
+ # Single-instance: bail if another wake is running.
32
+ exec 9>"$LOCKFILE"
33
+ if ! flock -n 9; then
34
+ echo "[wake $NOW] another instance running, exiting" >&2
35
+ exit 0
36
+ fi
37
+
38
+ # No queue file = nothing to do.
39
+ if [ ! -f "$QUEUE" ]; then
40
+ exit 0
41
+ fi
42
+
43
+ # Reconstruct status by folding all lines per id (latest wins) and filter
44
+ # to records whose `when` <= now AND status == "pending". One JSON object
45
+ # per output line.
46
+ PENDING=$(jq -n -c '
47
+ reduce inputs as $r ({};
48
+ .[$r.id] |= (. // {}) + $r
49
+ )
50
+ | to_entries
51
+ | map(.value)
52
+ | map(select(.status == "pending" and .when <= "'"$NOW"'"))
53
+ | .[]
54
+ ' < "$QUEUE")
55
+
56
+ if [ -z "$PENDING" ]; then
57
+ exit 0
58
+ fi
59
+
60
+ echo "$PENDING" | while IFS= read -r record; do
61
+ [ -z "$record" ] && continue
62
+
63
+ ID=$(echo "$record" | jq -r '.id')
64
+ ACTION=$(echo "$record" | jq -c '.action')
65
+
66
+ # Append "fired" status line first (defer queue is append-only).
67
+ printf '{"id":"%s","status":"fired","ts":"%s"}\n' "$ID" "$NOW" >> "$QUEUE"
68
+
69
+ # Invoke bareagent with the deferred action as stdin input.
70
+ # Run in background — wake script doesn't wait for completion.
71
+ ( echo "$ACTION" | bare-agent --config "$ORCHESTRATOR_CONFIG" \
72
+ >> "$LOG_DIR/fired-$ID.log" 2>&1
73
+ rc=$?
74
+ if [ $rc -ne 0 ]; then
75
+ printf '{"id":"%s","status":"failed","ts":"%s","exit_code":%d}\n' \
76
+ "$ID" "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" "$rc" >> "$QUEUE"
77
+ else
78
+ printf '{"id":"%s","status":"done","ts":"%s"}\n' \
79
+ "$ID" "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" >> "$QUEUE"
80
+ fi
81
+ ) &
82
+ done
83
+
84
+ wait
@@ -0,0 +1,65 @@
1
+ // examples/with-bareguard.mjs
2
+ //
3
+ // End-to-end: bareagent Loop + bareguard Gate.
4
+ // Runs a small LLM loop with budget cap, fs scope, audit log, and humanChannel.
5
+ //
6
+ // Run: OPENAI_API_KEY=... node examples/with-bareguard.mjs
7
+ //
8
+ // What this demonstrates:
9
+ // - Single-gate governance: every tool call traverses gate.check; every
10
+ // result reaches gate.record (via wrapTools).
11
+ // - Budget halt: if accumulated cost exceeds maxCostUsd, gate halts the loop.
12
+ // - Audit log: one JSONL line per gated event at ./bareagent-audit.jsonl.
13
+ // - humanChannel: required by bareguard. Here we auto-deny asks; in real use
14
+ // wire it to a chat platform, terminal prompt, etc.
15
+
16
+ import { Gate } from 'bareguard';
17
+ import { createRequire } from 'node:module';
18
+ const require = createRequire(import.meta.url);
19
+ const { Loop, wireGate } = require('bare-agent');
20
+ const { OpenAI } = require('bare-agent/providers');
21
+ const { createShellTools } = require('bare-agent/tools');
22
+
23
+ // 1. Build the gate. Every primitive is optional with sensible defaults.
24
+ const gate = new Gate({
25
+ budget: { maxCostUsd: 0.10 }, // hard USD cap
26
+ limits: { maxTurns: 20 }, // safety net on think/act cycles
27
+ fs: { readScope: ['/tmp', '~/'] }, // shell_read / shell_grep allowed roots
28
+ bash: { allow: ['ls', 'cat', 'echo', 'pwd'] }, // argv[0] allowlist for shell_run
29
+ audit: { path: './bareagent-audit.jsonl' },
30
+ // Required by bareguard: any ask/halt event flows through here.
31
+ // Auto-deny is the safest default for headless use; in real apps, wire to
32
+ // a Telegram/Slack/terminal prompt and return { decision: 'allow' | 'deny' }.
33
+ humanChannel: async (event) => {
34
+ console.warn(`[humanChannel] ${event.kind}: ${event.rule} — auto-denying`);
35
+ return { decision: 'deny' };
36
+ },
37
+ });
38
+ await gate.init();
39
+
40
+ // 2. Wire the gate into Loop's policy slot and wrap tools so gate.record fires.
41
+ const { policy, wrapTools } = wireGate(gate);
42
+
43
+ // 3. Standard bareagent setup.
44
+ const provider = new OpenAI({
45
+ apiKey: process.env.OPENAI_API_KEY,
46
+ model: 'gpt-4o-mini',
47
+ });
48
+ const { tools } = createShellTools();
49
+
50
+ const loop = new Loop({
51
+ provider,
52
+ policy,
53
+ onError: (err, meta) => console.error(`[onError ${meta.source}]`, err.message),
54
+ });
55
+
56
+ // 4. Run.
57
+ const result = await loop.run(
58
+ [{ role: 'user', content: 'List the contents of /tmp using shell_run with argv ["ls", "/tmp"].' }],
59
+ wrapTools(tools),
60
+ );
61
+
62
+ console.log('---');
63
+ console.log('text:', result.text);
64
+ console.log('cost:', result.cost?.toFixed(6) ?? 'n/a');
65
+ console.log('audit log → ./bareagent-audit.jsonl');
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "bare-agent",
3
- "version": "0.12.0",
3
+ "version": "0.12.2",
4
4
  "files": [
5
5
  "index.js",
6
6
  "index.d.ts",
7
+ "bareagent.context.md",
7
8
  "src/",
8
9
  "bin/",
9
10
  "tools/",
10
11
  "types/",
12
+ "examples/",
11
13
  "LICENSE",
12
14
  "NOTICE"
13
15
  ],
@@ -91,6 +93,7 @@
91
93
  "scripts": {
92
94
  "test": "node --test --test-force-exit test/**/*.test.js",
93
95
  "typecheck": "tsc --noEmit",
96
+ "prebuild:types": "node scripts/clean-types.js",
94
97
  "build:types": "tsc",
95
98
  "prepublishOnly": "npm run build:types"
96
99
  },
@@ -3,4 +3,4 @@ import { AnthropicProvider } from "./provider-anthropic";
3
3
  import { OllamaProvider } from "./provider-ollama";
4
4
  import { CLIPipeProvider } from "./provider-clipipe";
5
5
  import { FallbackProvider } from "./provider-fallback";
6
- export { OpenAIProvider as OpenAI, AnthropicProvider as Anthropic, OllamaProvider as Ollama, CLIPipeProvider as CLIPipe, FallbackProvider as Fallback };
6
+ export { OpenAIProvider as OpenAI, AnthropicProvider as Anthropic, OllamaProvider as Ollama, CLIPipeProvider as CLIPipe, FallbackProvider as Fallback, OpenAIProvider, AnthropicProvider, OllamaProvider, CLIPipeProvider, FallbackProvider };
package/src/providers.js CHANGED
@@ -7,9 +7,17 @@ const { CLIPipeProvider } = require('./provider-clipipe');
7
7
  const { FallbackProvider } = require('./provider-fallback');
8
8
 
9
9
  module.exports = {
10
+ // Short names (canonical — used throughout docs and the integration guide)
10
11
  OpenAI: OpenAIProvider,
11
12
  Anthropic: AnthropicProvider,
12
13
  Ollama: OllamaProvider,
13
14
  CLIPipe: CLIPipeProvider,
14
15
  Fallback: FallbackProvider,
16
+ // *Provider aliases match the class names in source/stack traces, so
17
+ // `const { OpenAIProvider } = require('bare-agent/providers')` also works.
18
+ OpenAIProvider,
19
+ AnthropicProvider,
20
+ OllamaProvider,
21
+ CLIPipeProvider,
22
+ FallbackProvider,
15
23
  };