arbiter-skill 0.1.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.
package/README.md ADDED
@@ -0,0 +1,142 @@
1
+ # Arbiter Skill
2
+
3
+ Agent-side CLI for pushing decisions to [Arbiter Zebu](https://github.com/5hanth/arbiter-zebu). Works with Clawdbot/OpenClaw agents or standalone.
4
+
5
+ ## Install
6
+
7
+ **Via ClawHub (for Clawdbot/OpenClaw):**
8
+ ```bash
9
+ clawhub install arbiter
10
+ ```
11
+
12
+ **Via npm/bun (standalone CLI):**
13
+ ```bash
14
+ bun add -g arbiter-skill
15
+ ```
16
+
17
+ ## Prerequisites
18
+
19
+ - [Arbiter Zebu](https://github.com/5hanth/arbiter-zebu) bot running (`bunx arbiter-zebu`)
20
+ - `~/.arbiter/queue/` directory (created automatically by the bot)
21
+
22
+ ## CLI Commands
23
+
24
+ ### arbiter-push
25
+
26
+ Push a decision plan for human review:
27
+
28
+ ```bash
29
+ arbiter-push '{
30
+ "title": "API Design Decisions",
31
+ "tag": "my-project",
32
+ "priority": "high",
33
+ "notify": "agent:swe1:main",
34
+ "decisions": [
35
+ {
36
+ "id": "auth",
37
+ "title": "Auth Method",
38
+ "context": "How to authenticate users",
39
+ "options": [
40
+ {"key": "jwt", "label": "JWT tokens"},
41
+ {"key": "session", "label": "Server sessions"},
42
+ {"key": "oauth", "label": "OAuth provider"}
43
+ ]
44
+ },
45
+ {
46
+ "id": "database",
47
+ "title": "Database Choice",
48
+ "context": "Primary datastore",
49
+ "options": [
50
+ {"key": "pg", "label": "PostgreSQL"},
51
+ {"key": "mongo", "label": "MongoDB"}
52
+ ]
53
+ }
54
+ ]
55
+ }'
56
+ ```
57
+
58
+ Returns:
59
+ ```json
60
+ {
61
+ "planId": "abc123",
62
+ "file": "~/.arbiter/queue/pending/ceo-api-design-abc123.md",
63
+ "total": 2,
64
+ "status": "pending"
65
+ }
66
+ ```
67
+
68
+ ### arbiter-status
69
+
70
+ Check plan status:
71
+
72
+ ```bash
73
+ arbiter-status '{"planId": "abc123"}'
74
+ # or by tag
75
+ arbiter-status '{"tag": "my-project"}'
76
+ ```
77
+
78
+ ### arbiter-get
79
+
80
+ Get answers from a completed plan:
81
+
82
+ ```bash
83
+ arbiter-get '{"planId": "abc123"}'
84
+ ```
85
+
86
+ Returns:
87
+ ```json
88
+ {
89
+ "planId": "abc123",
90
+ "status": "completed",
91
+ "answers": {
92
+ "auth": "jwt",
93
+ "database": "pg"
94
+ }
95
+ }
96
+ ```
97
+
98
+ ## How It Works
99
+
100
+ ```
101
+ arbiter-push writes markdown → ~/.arbiter/queue/pending/
102
+
103
+ Arbiter Zebu bot detects new file
104
+
105
+ Human reviews & answers in Telegram
106
+
107
+ On completion, notification written to
108
+ ~/.arbiter/queue/notify/
109
+
110
+ Agent picks up answers (heartbeat or poll)
111
+ ```
112
+
113
+ ## JSON Fields
114
+
115
+ ### Push args
116
+
117
+ | Field | Required | Description |
118
+ |-------|----------|-------------|
119
+ | `title` | Yes | Plan title |
120
+ | `tag` | No | Project tag for filtering |
121
+ | `context` | No | Background for the reviewer |
122
+ | `priority` | No | `low` / `normal` / `high` / `urgent` |
123
+ | `notify` | No | Session key to notify on completion |
124
+ | `decisions` | Yes | Array of decision objects |
125
+
126
+ ### Decision object
127
+
128
+ | Field | Required | Description |
129
+ |-------|----------|-------------|
130
+ | `id` | Yes | Unique ID within the plan |
131
+ | `title` | Yes | Human-readable title |
132
+ | `context` | No | Explanation for the reviewer |
133
+ | `options` | Yes | Array of `{key, label}` |
134
+ | `allowCustom` | No | Allow free-text answers |
135
+
136
+ ## Usage with Clawdbot
137
+
138
+ See [SKILL.md](./SKILL.md) for full agent integration docs.
139
+
140
+ ## License
141
+
142
+ MIT
package/SKILL.md ADDED
@@ -0,0 +1,291 @@
1
+ ---
2
+ name: arbiter
3
+ description: Push decisions to Arbiter Zebu for async human review. Use when you need human input on plans, architectural choices, or approval before proceeding.
4
+ metadata: {"openclaw":{"requires":{"bins":["arbiter-push"]}}}
5
+ ---
6
+
7
+ # Arbiter Skill
8
+
9
+ Push decisions to Arbiter Zebu for async human review. Use when you need human input on plans, architectural choices, or approval before proceeding.
10
+
11
+ ## Installation
12
+
13
+ **Quick install via ClawHub:**
14
+ ```bash
15
+ clawhub install arbiter
16
+ ```
17
+
18
+ **Or via bun (makes CLI commands available globally):**
19
+ ```bash
20
+ bun add -g arbiter-skill
21
+ ```
22
+
23
+ **Or manual:**
24
+ ```bash
25
+ git clone https://github.com/5hanth/arbiter-skill.git
26
+ cd arbiter-skill && npm install && npm run build
27
+ ln -s $(pwd) ~/.clawdbot/skills/arbiter
28
+ ```
29
+
30
+ ### Prerequisites
31
+
32
+ - [Arbiter Zebu](https://github.com/5hanth/arbiter-zebu) bot running (or just `bunx arbiter-zebu`)
33
+ - `~/.arbiter/queue/` directory (created automatically by the bot)
34
+
35
+ ## Environment Variables
36
+
37
+ Set these in your agent's environment for automatic agent/session detection:
38
+
39
+ | Variable | Description | Example |
40
+ |----------|-------------|---------|
41
+ | `CLAWDBOT_AGENT` | Agent ID | `ceo`, `swe1` |
42
+ | `CLAWDBOT_SESSION` | Session key | `agent:ceo:main` |
43
+
44
+ ## When to Use
45
+
46
+ - Plan review before implementation
47
+ - Architectural decisions with tradeoffs
48
+ - Anything blocking that needs human judgment
49
+ - Multiple related decisions as a batch
50
+
51
+ **Do NOT use for:**
52
+ - Simple yes/no that doesn't need explanation
53
+ - Urgent real-time decisions (use direct message instead)
54
+ - Technical questions you can research yourself
55
+
56
+ ## Tools
57
+
58
+ ### arbiter_push
59
+
60
+ Create a decision plan for human review.
61
+
62
+ **CLI:** `arbiter-push '<json>'` — takes a single JSON argument containing all fields.
63
+
64
+ ```bash
65
+ arbiter-push '{
66
+ "title": "API Design Decisions",
67
+ "tag": "nft-marketplace",
68
+ "context": "SWE2 needs these decided before API work",
69
+ "priority": "normal",
70
+ "notify": "agent:swe2:main",
71
+ "decisions": [
72
+ {
73
+ "id": "auth-strategy",
74
+ "title": "Auth Strategy",
75
+ "context": "How to authenticate admin users",
76
+ "options": [
77
+ {"key": "jwt", "label": "JWT tokens", "note": "Stateless"},
78
+ {"key": "session", "label": "Sessions", "note": "More control"},
79
+ {"key": "oauth", "label": "OAuth", "note": "External provider"}
80
+ ]
81
+ },
82
+ {
83
+ "id": "database",
84
+ "title": "Database Choice",
85
+ "context": "Primary datastore",
86
+ "options": [
87
+ {"key": "postgresql", "label": "PostgreSQL + JSONB"},
88
+ {"key": "mongodb", "label": "MongoDB"}
89
+ ],
90
+ "allowCustom": true
91
+ }
92
+ ]
93
+ }'
94
+ ```
95
+
96
+ **JSON Fields:**
97
+
98
+ | Field | Required | Description |
99
+ |-------|----------|-------------|
100
+ | `title` | Yes | Plan title |
101
+ | `tag` | No | Tag for filtering (e.g., project name) |
102
+ | `context` | No | Background for reviewer |
103
+ | `priority` | No | `low`, `normal`, `high`, `urgent` (default: normal) |
104
+ | `notify` | No | Session to notify when complete |
105
+ | `agent` | No | Agent ID (auto-detected from `CLAWDBOT_AGENT` env) |
106
+ | `session` | No | Session key (auto-detected from `CLAWDBOT_SESSION` env) |
107
+ | `decisions` | Yes | Array of decisions |
108
+
109
+ **Decision object:**
110
+
111
+ | Field | Required | Description |
112
+ |-------|----------|-------------|
113
+ | `id` | Yes | Unique ID within plan |
114
+ | `title` | Yes | Decision title |
115
+ | `context` | No | Explanation for reviewer |
116
+ | `options` | Yes | Array of `{key, label, note?}` |
117
+ | `allowCustom` | No | Allow free-text answer (default: false) |
118
+ | `default` | No | Suggested option key |
119
+
120
+ **Returns:**
121
+
122
+ ```json
123
+ {
124
+ "planId": "abc123",
125
+ "file": "~/.arbiter/queue/pending/ceo-api-design-abc123.md",
126
+ "total": 2,
127
+ "status": "pending"
128
+ }
129
+ ```
130
+
131
+ ### arbiter_status
132
+
133
+ Check the status of a decision plan.
134
+
135
+ **CLI:** `arbiter-status <plan-id>` or `arbiter-status --tag <tag>`
136
+
137
+ ```bash
138
+ arbiter-status abc12345
139
+ # or
140
+ arbiter-status --tag nft-marketplace
141
+ ```
142
+
143
+ **Returns:**
144
+
145
+ ```json
146
+ {
147
+ "planId": "abc123",
148
+ "title": "API Design Decisions",
149
+ "status": "in_progress",
150
+ "total": 3,
151
+ "answered": 1,
152
+ "remaining": 2,
153
+ "decisions": {
154
+ "auth-strategy": {"status": "answered", "answer": "jwt"},
155
+ "database": {"status": "pending", "answer": null},
156
+ "caching": {"status": "pending", "answer": null}
157
+ }
158
+ }
159
+ ```
160
+
161
+ ### arbiter_get
162
+
163
+ Get answers from a completed plan.
164
+
165
+ **CLI:** `arbiter-get <plan-id>` or `arbiter-get --tag <tag>`
166
+
167
+ ```bash
168
+ arbiter-get abc12345
169
+ # or
170
+ arbiter-get --tag nft-marketplace
171
+ ```
172
+
173
+ **Returns:**
174
+
175
+ ```json
176
+ {
177
+ "planId": "abc123",
178
+ "status": "completed",
179
+ "completedAt": "2026-01-30T01:45:00Z",
180
+ "answers": {
181
+ "auth-strategy": "jwt",
182
+ "database": "postgresql",
183
+ "caching": "redis"
184
+ }
185
+ }
186
+ ```
187
+
188
+ **Error if not complete:**
189
+
190
+ ```json
191
+ {
192
+ "error": "Plan not complete",
193
+ "status": "in_progress",
194
+ "remaining": 2
195
+ }
196
+ ```
197
+
198
+ ### arbiter_await
199
+
200
+ Block until plan is complete (with timeout).
201
+
202
+ ```bash
203
+ arbiter-await abc12345 --timeout 3600
204
+ ```
205
+
206
+ Polls every 30 seconds until complete or timeout.
207
+
208
+ **Returns:** Same as `arbiter_get` on completion.
209
+
210
+ ## Usage Examples
211
+
212
+ ### Example 1: Plan Review
213
+
214
+ ```bash
215
+ # Push plan decisions (single JSON argument)
216
+ RESULT=$(arbiter-push '{"title":"Clean IT i18n Plan","tag":"clean-it","priority":"high","notify":"agent:swe3:main","decisions":[{"id":"library","title":"i18n Library","options":[{"key":"i18next","label":"i18next"},{"key":"formatjs","label":"FormatJS"}]},{"id":"keys","title":"Key Structure","options":[{"key":"flat","label":"Flat (login.button)"},{"key":"nested","label":"Nested ({login:{button}})"}]}]}')
217
+
218
+ PLAN_ID=$(echo $RESULT | jq -r '.planId')
219
+ echo "Pushed plan $PLAN_ID — waiting for human review"
220
+ ```
221
+
222
+ ### Example 2: Check and Proceed
223
+
224
+ ```bash
225
+ # Check if decisions are ready
226
+ STATUS=$(arbiter-status --tag nft-marketplace)
227
+
228
+ if [ "$(echo $STATUS | jq -r '.status')" == "completed" ]; then
229
+ ANSWERS=$(arbiter-get --tag nft-marketplace)
230
+ AUTH=$(echo $ANSWERS | jq -r '.answers["auth-strategy"]')
231
+ echo "Using auth strategy: $AUTH"
232
+ # Proceed with implementation
233
+ else
234
+ echo "Still waiting for $(echo $STATUS | jq -r '.remaining') decisions"
235
+ fi
236
+ ```
237
+
238
+ ### Example 3: Blocking Wait
239
+
240
+ ```bash
241
+ # Wait up to 1 hour for decisions
242
+ ANSWERS=$(arbiter-await abc12345 --timeout 3600)
243
+
244
+ if [ $? -eq 0 ]; then
245
+ # Got answers, proceed
246
+ echo "Decisions ready: $ANSWERS"
247
+ else
248
+ echo "Timeout waiting for decisions"
249
+ fi
250
+ ```
251
+
252
+ ## Best Practices
253
+
254
+ 1. **Batch related decisions** — Don't push one at a time
255
+ 2. **Provide context** — Human needs to understand tradeoffs
256
+ 3. **Use tags** — Makes filtering easy (`--tag project-name`)
257
+ 4. **Set notify** — So blocked agents get woken up
258
+ 5. **Use priority sparingly** — Reserve `urgent` for true blockers
259
+
260
+ ## File Locations
261
+
262
+ | Path | Purpose |
263
+ |------|---------|
264
+ | `~/.arbiter/queue/pending/` | Plans awaiting review |
265
+ | `~/.arbiter/queue/completed/` | Answered plans (archive) |
266
+ | `~/.arbiter/queue/notify/` | Agent notifications |
267
+
268
+ ## Checking Notifications (Agent Heartbeat)
269
+
270
+ In your HEARTBEAT.md, add:
271
+
272
+ ```markdown
273
+ ## Check Arbiter Notifications
274
+
275
+ 1. Check if `~/.arbiter/queue/notify/` has files for my session
276
+ 2. If yes, read answers and proceed with blocked work
277
+ 3. Delete notification file after processing
278
+ ```
279
+
280
+ ## Troubleshooting
281
+
282
+ | Issue | Solution |
283
+ |-------|----------|
284
+ | Plan not showing in Arbiter | Check file is valid YAML frontmatter |
285
+ | Answers not appearing | Check `arbiter_status`, may be incomplete |
286
+ | Notification not received | Ensure `--notify` was set correctly |
287
+
288
+ ## See Also
289
+
290
+ - [Arbiter Zebu Architecture](https://github.com/5hanth/arbiter-zebu/blob/main/ARCHITECTURE.md)
291
+ - [Arbiter Zebu Bot](https://github.com/5hanth/arbiter-zebu)
package/dist/get.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * arbiter get - Retrieve answers from a completed decision plan
4
+ *
5
+ * Usage: arbiter-get <plan-id> [--tag <tag>]
6
+ *
7
+ * Returns JSON with:
8
+ * - planId: Plan ID
9
+ * - status: completed (or error if not complete)
10
+ * - completedAt: ISO timestamp
11
+ * - answers: Map of decision ID -> answer
12
+ */
13
+ export {};
package/dist/get.js ADDED
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * arbiter get - Retrieve answers from a completed decision plan
4
+ *
5
+ * Usage: arbiter-get <plan-id> [--tag <tag>]
6
+ *
7
+ * Returns JSON with:
8
+ * - planId: Plan ID
9
+ * - status: completed (or error if not complete)
10
+ * - completedAt: ISO timestamp
11
+ * - answers: Map of decision ID -> answer
12
+ */
13
+ import { findPlanFile, parsePlanFile, parseDecisions } from './utils.js';
14
+ /**
15
+ * Get answers from a completed decision plan
16
+ */
17
+ function get(planId, tag) {
18
+ if (!planId && !tag) {
19
+ return { error: 'Either planId or tag is required' };
20
+ }
21
+ const file = findPlanFile(planId, tag);
22
+ if (!file) {
23
+ return { error: 'Plan not found' };
24
+ }
25
+ const { frontmatter, content } = parsePlanFile(file);
26
+ if (frontmatter.status !== 'completed') {
27
+ return {
28
+ error: `Plan not complete (status: ${frontmatter.status})`,
29
+ planId: frontmatter.id,
30
+ status: frontmatter.status,
31
+ completedAt: '',
32
+ answers: {}
33
+ };
34
+ }
35
+ const decisions = parseDecisions(content);
36
+ const answers = {};
37
+ for (const d of decisions) {
38
+ if (d.answer !== null) {
39
+ answers[d.id] = d.answer;
40
+ }
41
+ }
42
+ return {
43
+ planId: frontmatter.id,
44
+ status: 'completed',
45
+ completedAt: frontmatter.completed_at || '',
46
+ answers
47
+ };
48
+ }
49
+ // CLI entry point
50
+ function main() {
51
+ const args = process.argv.slice(2);
52
+ if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
53
+ console.log(`
54
+ arbiter get - Retrieve answers from a completed decision plan
55
+
56
+ Usage: arbiter-get <plan-id>
57
+ arbiter-get --tag <tag>
58
+
59
+ Example:
60
+ arbiter-get abc12345
61
+ arbiter-get --tag nft-marketplace
62
+
63
+ Note: Returns error if plan is not yet completed.
64
+ `);
65
+ process.exit(0);
66
+ }
67
+ let planId;
68
+ let tag;
69
+ for (let i = 0; i < args.length; i++) {
70
+ if (args[i] === '--tag' && args[i + 1]) {
71
+ tag = args[i + 1];
72
+ i++;
73
+ }
74
+ else if (!args[i].startsWith('-')) {
75
+ planId = args[i];
76
+ }
77
+ }
78
+ const result = get(planId, tag);
79
+ console.log(JSON.stringify(result, null, 2));
80
+ if ('error' in result) {
81
+ process.exit(1);
82
+ }
83
+ }
84
+ main();
package/dist/push.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * arbiter push - Create a decision file in the queue
4
+ *
5
+ * Usage: arbiter-push <json-args>
6
+ *
7
+ * The JSON should contain:
8
+ * - title: Plan title (required)
9
+ * - tag: Project tag (optional)
10
+ * - context: Context for reviewer (optional)
11
+ * - priority: low|normal|high|urgent (optional, default: normal)
12
+ * - notify: Session to notify on completion (optional)
13
+ * - agent: Agent ID (optional, uses CLAWDBOT_AGENT env)
14
+ * - session: Session key (optional, uses CLAWDBOT_SESSION env)
15
+ * - decisions: Array of decisions (required)
16
+ *
17
+ * Each decision:
18
+ * - id: Unique ID within the plan
19
+ * - title: Decision title
20
+ * - context: Context for this decision
21
+ * - options: Array of { key, label, note? }
22
+ * - allowCustom: Allow custom text answer (optional)
23
+ */
24
+ export {};
package/dist/push.js ADDED
@@ -0,0 +1,143 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * arbiter push - Create a decision file in the queue
4
+ *
5
+ * Usage: arbiter-push <json-args>
6
+ *
7
+ * The JSON should contain:
8
+ * - title: Plan title (required)
9
+ * - tag: Project tag (optional)
10
+ * - context: Context for reviewer (optional)
11
+ * - priority: low|normal|high|urgent (optional, default: normal)
12
+ * - notify: Session to notify on completion (optional)
13
+ * - agent: Agent ID (optional, uses CLAWDBOT_AGENT env)
14
+ * - session: Session key (optional, uses CLAWDBOT_SESSION env)
15
+ * - decisions: Array of decisions (required)
16
+ *
17
+ * Each decision:
18
+ * - id: Unique ID within the plan
19
+ * - title: Decision title
20
+ * - context: Context for this decision
21
+ * - options: Array of { key, label, note? }
22
+ * - allowCustom: Allow custom text answer (optional)
23
+ */
24
+ import { writeFileSync } from 'node:fs';
25
+ import { join } from 'node:path';
26
+ import { nanoid } from 'nanoid';
27
+ import { getQueueDir, ensureQueueDirs, slugify, nowISO } from './utils.js';
28
+ /**
29
+ * Generate the markdown content for a decision plan
30
+ */
31
+ function generateMarkdown(args) {
32
+ const now = nowISO();
33
+ const total = args.decisions.length;
34
+ // Build frontmatter
35
+ const frontmatter = `---
36
+ id: ${args.id}
37
+ version: 1
38
+ agent: ${args.agent}
39
+ session: ${args.session}
40
+ tag: ${args.tag || 'general'}
41
+ title: "${args.title}"
42
+ priority: ${args.priority || 'normal'}
43
+ status: pending
44
+ created_at: ${now}
45
+ updated_at: ${now}
46
+ completed_at: null
47
+ total: ${total}
48
+ answered: 0
49
+ remaining: ${total}
50
+ ${args.notify ? `notify_session: ${args.notify}` : ''}
51
+ ---`;
52
+ // Build context section
53
+ const contextSection = `
54
+ # ${args.title}
55
+
56
+ ${args.context || 'Please review and answer the following decisions.'}
57
+ `;
58
+ // Build decision sections
59
+ const decisionSections = args.decisions.map((d, i) => {
60
+ const optionsMarkdown = d.options
61
+ .map(o => `- \`${o.key}\` — ${o.label}${o.note ? ` (${o.note})` : ''}`)
62
+ .join('\n');
63
+ return `
64
+ ---
65
+
66
+ ## Decision ${i + 1}: ${d.title}
67
+
68
+ id: ${d.id}
69
+ status: pending
70
+ answer: null
71
+ answered_at: null
72
+ ${d.allowCustom ? 'allow_custom: true' : ''}
73
+
74
+ **Context:** ${d.context}
75
+
76
+ **Options:**
77
+ ${optionsMarkdown}
78
+ `;
79
+ }).join('\n');
80
+ return frontmatter + contextSection + decisionSections;
81
+ }
82
+ /**
83
+ * Push a decision plan to the queue
84
+ */
85
+ function push(args) {
86
+ // Validate required fields
87
+ if (!args.title) {
88
+ throw new Error('title is required');
89
+ }
90
+ if (!args.decisions || args.decisions.length === 0) {
91
+ throw new Error('decisions array is required and must not be empty');
92
+ }
93
+ // Validate each decision
94
+ for (const d of args.decisions) {
95
+ if (!d.id || !d.title || !d.options || d.options.length === 0) {
96
+ throw new Error(`Invalid decision: ${JSON.stringify(d)}`);
97
+ }
98
+ }
99
+ const id = nanoid(8);
100
+ const agent = args.agent || process.env.CLAWDBOT_AGENT || 'unknown';
101
+ const session = args.session || process.env.CLAWDBOT_SESSION || 'unknown';
102
+ const filename = `${agent}-${slugify(args.title)}-${id}.md`;
103
+ const filepath = join(getQueueDir('pending'), filename);
104
+ const content = generateMarkdown({
105
+ ...args,
106
+ id,
107
+ agent,
108
+ session
109
+ });
110
+ ensureQueueDirs();
111
+ writeFileSync(filepath, content, 'utf-8');
112
+ return {
113
+ planId: id,
114
+ file: filepath,
115
+ total: args.decisions.length,
116
+ status: 'pending'
117
+ };
118
+ }
119
+ // CLI entry point
120
+ function main() {
121
+ const args = process.argv.slice(2);
122
+ if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
123
+ console.log(`
124
+ arbiter push - Create a decision file in the queue
125
+
126
+ Usage: arbiter-push '<json>'
127
+
128
+ Example:
129
+ arbiter-push '{"title":"API Decisions","decisions":[{"id":"auth","title":"Auth Method","context":"Choose auth","options":[{"key":"jwt","label":"JWT tokens"},{"key":"session","label":"Sessions"}]}]}'
130
+ `);
131
+ process.exit(0);
132
+ }
133
+ try {
134
+ const input = JSON.parse(args.join(' '));
135
+ const result = push(input);
136
+ console.log(JSON.stringify(result, null, 2));
137
+ }
138
+ catch (err) {
139
+ console.error('Error:', err instanceof Error ? err.message : err);
140
+ process.exit(1);
141
+ }
142
+ }
143
+ main();