@hung319/opencode-hive 1.5.6 → 1.5.9

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 CHANGED
@@ -14,6 +14,49 @@ Vibe: "Just make it work"
14
14
  Hive: Plan → Review → Approve → Execute → Ship
15
15
  ```
16
16
 
17
+ ## Quick Setup (3 Steps)
18
+
19
+ ### For AI Agents (LLM)
20
+
21
+ ```
22
+ 1. Run: hive_doctor
23
+ 2. Install missing: npm install <packages> && npx -y <tools>
24
+ 3. Config: Add to ~/.config/opencode/agent_hive.json
25
+ ```
26
+
27
+ ### For Humans
28
+
29
+ **Step 1: Check if your system is ready** (run BEFORE installing)
30
+ ```bash
31
+ # Run standalone doctor to see what's needed
32
+ bunx @hung319/opencode-hive doctor
33
+ # or
34
+ npx @hung319/opencode-hive doctor
35
+ ```
36
+
37
+ **Step 2: Install the plugin**
38
+ ```bash
39
+ npm install @hung319/opencode-hive
40
+ ```
41
+
42
+ **Step 3: Install extras you want**
43
+ - For **code analysis**: `npm install @notprolands/ast-grep-mcp`
44
+ - For **fast code search**: `npm install @paretools/search`
45
+ - For **code navigation**: `npx -y @butttons/dora`
46
+ - For **auto code review**: `npx -y auto-cr-cmd`
47
+ - For **blockchain tasks**: `npm install btca-ask`
48
+
49
+ **Step 4: Optional config**
50
+ Create `~/.config/opencode/agent_hive.json`:
51
+ ```json
52
+ {
53
+ "snip": { "enabled": true },
54
+ "vectorMemory": { "enabled": true }
55
+ }
56
+ ```
57
+
58
+ ---
59
+
17
60
  ## Installation
18
61
 
19
62
  ```bash
@@ -489,71 +532,112 @@ hive_vector_search({
489
532
 
490
533
  ## Hive Doctor
491
534
 
492
- System health check and optimization advisor. Checks dependencies, features, and provides recommendations.
535
+ System health check with actionable fixes. Run this when setting up or troubleshooting.
493
536
 
494
537
  ### Tools
495
538
 
496
539
  | Tool | Description |
497
540
  |------|-------------|
498
- | `hive_doctor` | Full health check with recommendations |
541
+ | `hive_doctor` | Full health check with install commands |
499
542
  | `hive_doctor_quick` | Quick status summary |
500
543
 
501
544
  ### Usage
502
545
 
503
546
  ```typescript
504
- // Full health check
547
+ // Full health check with actionable output
505
548
  hive_doctor()
506
549
 
507
- // Quick check
550
+ // Quick status
508
551
  hive_doctor_quick()
509
552
  ```
510
553
 
554
+ **Standalone (before installing):**
555
+ ```bash
556
+ bunx @hung319/opencode-hive doctor
557
+ ```
558
+
511
559
  ### What it checks
512
560
 
513
- 1. **Dependencies** - Optional packages installed and working
514
- - @sparkleideas/agent-booster
515
- - @sparkleideas/memory
516
- - @ast-grep/napi
517
- - @paretools/search
518
- - @upstash/context7-mcp
519
- - exa-mcp-server
561
+ 1. **Dependencies** - npm packages installed?
562
+ - Core: `@ast-grep/napi`, `@notprolands/ast-grep-mcp`, `@paretools/search`
563
+ - Agent: `@sparkleideas/agent-booster`, `@sparkleideas/memory`
564
+ - MCPs: `@upstash/context7-mcp`, `exa-mcp-server`, `grep-mcp`
565
+ - Blockchain: `btca-ask`, `opencode-model-selector`
566
+
567
+ 2. **CLI Tools** - npx tools available?
568
+ - `dora` - Code navigation (SCIP-based)
569
+ - `auto-cr` - Automated code review (SWC)
570
+ - `scip-typescript` - TypeScript indexer
571
+ - `veil` - Code discovery
572
+ - `btca` - BTC/A blockchain agent
520
573
 
521
- 2. **Optimizations** - Features enabled in config
522
- - snip (60-90% token reduction)
523
- - vector memory (semantic search)
524
- - agent booster (fast code editing)
525
- - Docker sandbox (isolated environments)
526
- - native ast-grep (fast AST analysis)
527
- - pare-search (structured search)
574
+ 3. **Native Binaries** - @ast-grep/napi tree-sitter?
575
+ - Native mode: Fastest, uses compiled binaries
576
+ - CLI mode: Falls back to MCP via npx
528
577
 
529
- 3. **Recommendations** - Suggestions for improvements
578
+ 4. **Config** - Features enabled?
579
+ - snip, vectorMemory, agentBooster
580
+ - sandbox mode
581
+ - MCPs: ast_grep, veil, pare_search
530
582
 
531
583
  ### Example Output
532
584
 
533
585
  ```json
534
586
  {
535
587
  "status": "warning",
536
- "checks": {
537
- "dependencies": {
538
- "total": 6,
539
- "installed": 4,
540
- "packages": [...]
588
+ "summary": {
589
+ "dependencies": "⚠️ 2 missing: agent-booster, vector-memory",
590
+ "cliTools": "⚠️ 1 missing: auto-cr",
591
+ "nativeBinaries": "⚡ CLI mode (native unavailable)",
592
+ "config": "💡 2 disabled: snip, vectorMemory"
593
+ },
594
+ "actionItems": [
595
+ {
596
+ "priority": "high",
597
+ "action": "Install auto-cr",
598
+ "command": "npx -y auto-cr-cmd",
599
+ "reason": "SWC-based automated code review"
541
600
  },
542
- "optimizations": {
543
- "total": 6,
544
- "enabled": 3,
545
- "features": [...]
601
+ {
602
+ "priority": "medium",
603
+ "action": "Install agent-booster",
604
+ "command": "npm install @sparkleideas/agent-booster",
605
+ "reason": "52x faster code editing"
546
606
  }
547
- },
548
- "recommendations": [
549
- "Enable vector memory for semantic search across memories"
550
607
  ],
551
- "quickFixes": [
552
- { "command": "npm install @sparkleideas/memory", "description": "Install vector-memory" }
553
- ]
608
+ "quickInstall": {
609
+ "deps": ["@sparkleideas/agent-booster", "@sparkleideas/memory"],
610
+ "cliTools": ["auto-cr-cmd"]
611
+ }
554
612
  }
555
613
  ```
556
614
 
615
+ ### Setup Workflow
616
+
617
+ **For AI Agents (LLM):**
618
+
619
+ ```
620
+ 1. Run: hive_doctor
621
+ 2. Parse: actionItems[] for priority: "high"
622
+ 3. Install: Run quickInstall.commands
623
+ 4. Config: Apply config recommendations
624
+ 5. Verify: Run hive_doctor again to confirm
625
+ ```
626
+
627
+ **For Humans:**
628
+
629
+ 1. **Open OpenCode** and ask "Run hive_doctor"
630
+ 2. **Look at the summary** - it tells you what's missing
631
+ 3. **Install what you need** - commands are ready to copy
632
+ 4. **Optional: Configure** - enable snip, vector memory for extra features
633
+
634
+ ```
635
+ Quick Install All:
636
+ npm install @notprolands/ast-grep-mcp @paretools/search @sparkleideas/memory
637
+ npx -y @butttons/dora auto-cr-cmd
638
+ ```
639
+ ```
640
+
557
641
  ## License
558
642
 
559
643
  MIT with Commons Clause — Free for personal and non-commercial use. See [LICENSE](../../LICENSE) for details.
package/bin/doctor.ts ADDED
@@ -0,0 +1,436 @@
1
+ #!/usr/bin/env bun
2
+
3
+ /**
4
+ * Hive Doctor - Standalone version
5
+ *
6
+ * Run BEFORE installing the plugin to check if your system is ready:
7
+ *
8
+ * bunx @hung319/opencode-hive doctor
9
+ * npx @hung319/opencode-hive doctor
10
+ *
11
+ * Or install and run:
12
+ *
13
+ * npm install @hung319/opencode-hive
14
+ * hive_doctor() // via OpenCode
15
+ */
16
+
17
+ import { execSync } from 'child_process';
18
+ import * as fs from 'fs';
19
+ import * as path from 'path';
20
+
21
+ // ============================================================================
22
+ // Types
23
+ // ============================================================================
24
+
25
+ interface CheckResult {
26
+ name: string;
27
+ installed: boolean;
28
+ version?: string;
29
+ reason?: string;
30
+ }
31
+
32
+ interface CliCheck {
33
+ name: string;
34
+ command: string;
35
+ installed: boolean;
36
+ version?: string;
37
+ description: string;
38
+ }
39
+
40
+ interface DoctorOutput {
41
+ status: 'ready' | 'needs-setup' | 'action-required';
42
+ version: string;
43
+ summary: {
44
+ os: string;
45
+ nodeVersion: string;
46
+ packageManager: string;
47
+ };
48
+ checks: {
49
+ dependencies: {
50
+ total: number;
51
+ installed: number;
52
+ items: CheckResult[];
53
+ };
54
+ cliTools: {
55
+ total: number;
56
+ available: number;
57
+ items: CliCheck[];
58
+ };
59
+ nativeBinaries: {
60
+ status: 'native' | 'cli-mode';
61
+ reason?: string;
62
+ };
63
+ config: {
64
+ exists: boolean;
65
+ path?: string;
66
+ optimizations: string[];
67
+ };
68
+ };
69
+ actionItems: {
70
+ priority: 'critical' | 'high' | 'medium' | 'low';
71
+ action: string;
72
+ command?: string;
73
+ reason: string;
74
+ }[];
75
+ installCommands: {
76
+ deps: string;
77
+ cliTools: string;
78
+ };
79
+ }
80
+
81
+ // ============================================================================
82
+ // Color helpers
83
+ // ============================================================================
84
+
85
+ const colors = {
86
+ green: (text: string) => `\x1b[32m${text}\x1b[0m`,
87
+ yellow: (text: string) => `\x1b[33m${text}\x1b[0m`,
88
+ red: (text: string) => `\x1b[31m${text}\x1b[0m`,
89
+ blue: (text: string) => `\x1b[34m${text}\x1b[0m`,
90
+ gray: (text: string) => `\x1b[90m${text}\x1b[0m`,
91
+ };
92
+
93
+ // ============================================================================
94
+ // Check functions
95
+ // ============================================================================
96
+
97
+ function getSystemInfo() {
98
+ return {
99
+ os: process.platform,
100
+ nodeVersion: process.version,
101
+ packageManager: exists('npm') ? 'npm' : exists('bun') ? 'bun' : 'unknown',
102
+ };
103
+ }
104
+
105
+ function exists(cmd: string): boolean {
106
+ try {
107
+ execSync(cmd, { stdio: 'ignore' });
108
+ return true;
109
+ } catch {
110
+ return false;
111
+ }
112
+ }
113
+
114
+ function checkNpmPackage(name: string): CheckResult {
115
+ const result: CheckResult = { name, installed: false };
116
+
117
+ try {
118
+ const output = execSync(`npm list ${name} --depth=0 --json 2>/dev/null`, {
119
+ encoding: 'utf-8',
120
+ timeout: 10000,
121
+ });
122
+ const json = JSON.parse(output);
123
+ if (json.dependencies && json.dependencies[name]) {
124
+ result.installed = true;
125
+ result.version = json.dependencies[name].version;
126
+ }
127
+ } catch {}
128
+
129
+ return result;
130
+ }
131
+
132
+ function checkCliTool(name: string, command: string, description: string): CliCheck {
133
+ const result: CliCheck = { name, command, installed: false, description };
134
+
135
+ // Try direct command
136
+ try {
137
+ const cmd = command.split(' ')[0];
138
+ execSync(cmd, { stdio: 'ignore', timeout: 3000 });
139
+ result.installed = true;
140
+ result.version = 'installed';
141
+ return result;
142
+ } catch {}
143
+
144
+ // Try npx
145
+ try {
146
+ execSync(`npx -y ${command.split(' ')[0]} --version`, {
147
+ stdio: 'ignore',
148
+ timeout: 10000
149
+ });
150
+ result.installed = true;
151
+ result.version = 'via npx';
152
+ return result;
153
+ } catch {}
154
+
155
+ return result;
156
+ }
157
+
158
+ function checkAstGrepNative(): { status: 'native' | 'cli-mode'; reason?: string } {
159
+ // Check if @ast-grep/napi package exists with native binaries
160
+ const napiDirs = [
161
+ path.join(process.cwd(), 'node_modules/@ast-grep/napi'),
162
+ path.join(process.env.HOME || '', '.npm-global/lib/node_modules/@ast-grep/napi'),
163
+ ];
164
+
165
+ for (const napiDir of napiDirs) {
166
+ if (!fs.existsSync(napiDir)) continue;
167
+
168
+ const binaryPaths = [
169
+ path.join(napiDir, 'index.node'),
170
+ path.join(napiDir, 'build/Release/ast_grep.node'),
171
+ path.join(napiDir, 'dist/index.node'),
172
+ ];
173
+
174
+ const hasBinary = binaryPaths.some(p => fs.existsSync(p));
175
+
176
+ if (hasBinary) {
177
+ return { status: 'native' };
178
+ }
179
+ }
180
+
181
+ return {
182
+ status: 'cli-mode',
183
+ reason: 'Native binaries not found (tree-sitter compilation may have failed)'
184
+ };
185
+ }
186
+
187
+ function checkConfig(): { exists: boolean; path?: string; optimizations: string[] } {
188
+ const configPaths = [
189
+ path.join(process.env.HOME || '', '.config/opencode/agent_hive.json'),
190
+ path.join(process.env.HOME || '', '.config/opencode/agent_hive.jsonc'),
191
+ ];
192
+
193
+ for (const configPath of configPaths) {
194
+ if (fs.existsSync(configPath)) {
195
+ try {
196
+ const content = fs.readFileSync(configPath, 'utf-8');
197
+ const config = JSON.parse(content.replace(/\\/g, ''));
198
+ const optimizations: string[] = [];
199
+
200
+ if (config.snip?.enabled) optimizations.push('snip');
201
+ if (config.vectorMemory?.enabled) optimizations.push('vectorMemory');
202
+ if (config.agentBooster?.enabled !== false) optimizations.push('agentBooster');
203
+ if (config.sandbox?.mode !== 'none') optimizations.push('sandbox');
204
+
205
+ return { exists: true, path: configPath, optimizations };
206
+ } catch {}
207
+ }
208
+ }
209
+
210
+ return { exists: false, optimizations: [] };
211
+ }
212
+
213
+ // ============================================================================
214
+ // Main check
215
+ // ============================================================================
216
+
217
+ function runDoctor(): DoctorOutput {
218
+ const output: DoctorOutput = {
219
+ status: 'ready',
220
+ version: '1.5.8',
221
+ summary: getSystemInfo(),
222
+ checks: {
223
+ dependencies: { total: 0, installed: 0, items: [] },
224
+ cliTools: { total: 0, available: 0, items: [] },
225
+ nativeBinaries: { status: 'cli-mode' },
226
+ config: { exists: false, optimizations: [] },
227
+ },
228
+ actionItems: [],
229
+ installCommands: { deps: '', cliTools: '' },
230
+ };
231
+
232
+ // Check dependencies
233
+ const deps = [
234
+ '@ast-grep/napi',
235
+ '@notprolands/ast-grep-mcp',
236
+ '@sparkleideas/agent-booster',
237
+ '@sparkleideas/memory',
238
+ '@paretools/search',
239
+ '@upstash/context7-mcp',
240
+ 'exa-mcp-server',
241
+ 'grep-mcp',
242
+ 'btca-ask',
243
+ 'opencode-model-selector',
244
+ ];
245
+
246
+ output.checks.dependencies.items = deps.map(d => checkNpmPackage(d));
247
+ output.checks.dependencies.total = deps.length;
248
+ output.checks.dependencies.installed = output.checks.dependencies.items.filter(d => d.installed).length;
249
+
250
+ // Check CLI tools
251
+ const cliTools = [
252
+ { name: 'dora', command: '@butttons/dora', description: 'SCIP-based code navigation' },
253
+ { name: 'auto-cr', command: 'auto-cr-cmd', description: 'SWC-based automated code review' },
254
+ { name: 'veil', command: '@ushiradineth/veil', description: 'Code discovery and retrieval' },
255
+ { name: 'scip-typescript', command: '@sourcegraph/scip-typescript', description: 'TypeScript SCIP indexer' },
256
+ { name: 'btca', command: 'btca-ask', description: 'BTC/A agent for blockchain tasks' },
257
+ { name: 'ast-grep', command: '@notprolands/ast-grep-mcp', description: 'AST-based pattern matching' },
258
+ ];
259
+
260
+ output.checks.cliTools.items = cliTools.map(t => checkCliTool(t.name, t.command, t.description));
261
+ output.checks.cliTools.total = cliTools.length;
262
+ output.checks.cliTools.available = output.checks.cliTools.items.filter(t => t.installed).length;
263
+
264
+ // Check native binaries
265
+ output.checks.nativeBinaries = checkAstGrepNative();
266
+
267
+ // Check config
268
+ output.checks.config = checkConfig();
269
+
270
+ // Generate action items
271
+ const missingDeps = output.checks.dependencies.items.filter(d => !d.installed);
272
+ const missingTools = output.checks.cliTools.items.filter(t => !t.installed);
273
+
274
+ if (missingTools.length > 0) {
275
+ output.actionItems.push({
276
+ priority: 'high',
277
+ action: `Install ${missingTools.length} CLI tool(s)`,
278
+ command: missingTools.map(t => `npx -y ${t.command}`).join(' && '),
279
+ reason: 'CLI tools provide code navigation, review, and analysis features',
280
+ });
281
+ }
282
+
283
+ if (missingDeps.length > 0) {
284
+ const important = missingDeps.filter(d =>
285
+ ['@ast-grep/napi', '@notprolands/ast-grep-mcp', '@paretools/search'].includes(d.name)
286
+ );
287
+
288
+ if (important.length > 0) {
289
+ output.actionItems.push({
290
+ priority: 'medium',
291
+ action: `Install ${important.length} important package(s)`,
292
+ command: important.map(d => `npm install ${d.name}`).join(' && '),
293
+ reason: 'These packages enable core functionality',
294
+ });
295
+ }
296
+ }
297
+
298
+ if (!output.checks.config.exists) {
299
+ output.actionItems.push({
300
+ priority: 'low',
301
+ action: 'Create config file',
302
+ command: `mkdir -p ~/.config/opencode && cat > ~/.config/opencode/agent_hive.json << 'EOF'\n{\n "snip": { "enabled": true },\n "vectorMemory": { "enabled": true }\n}\nEOF`,
303
+ reason: 'Enable optimizations for better performance',
304
+ });
305
+ }
306
+
307
+ // Generate install commands
308
+ if (missingDeps.length > 0) {
309
+ output.installCommands.deps = `npm install ${missingDeps.map(d => d.name).join(' ')}`;
310
+ }
311
+
312
+ if (missingTools.length > 0) {
313
+ output.installCommands.cliTools = `npx -y ${missingTools.map(t => t.command.split(' ')[0]).join(' ')}`;
314
+ }
315
+
316
+ // Determine status
317
+ if (output.actionItems.some(a => a.priority === 'critical')) {
318
+ output.status = 'action-required';
319
+ } else if (output.actionItems.some(a => a.priority === 'high' || a.priority === 'medium')) {
320
+ output.status = 'needs-setup';
321
+ }
322
+
323
+ return output;
324
+ }
325
+
326
+ // ============================================================================
327
+ // Print output
328
+ // ============================================================================
329
+
330
+ function printDoctor(output: DoctorOutput) {
331
+ console.log('\n' + colors.blue('╔═══════════════════════════════════════════════════════════╗'));
332
+ console.log(colors.blue('║') + ' 🐝 Hive Doctor v' + output.version + ' - System Check' + ' '.repeat(14) + colors.blue('║'));
333
+ console.log(colors.blue('╚═══════════════════════════════════════════════════════════╝'));
334
+
335
+ // Summary
336
+ console.log('\n' + colors.gray('─'.repeat(55)));
337
+ console.log(` OS: ${output.summary.os}`);
338
+ console.log(` Node: ${output.summary.nodeVersion}`);
339
+ console.log(` Package Manager: ${output.summary.packageManager}`);
340
+ console.log(colors.gray('─'.repeat(55)));
341
+
342
+ // Status
343
+ const statusColor = output.status === 'ready' ? colors.green :
344
+ output.status === 'needs-setup' ? colors.yellow : colors.red;
345
+ const statusText = output.status === 'ready' ? '✅ READY' :
346
+ output.status === 'needs-setup' ? '⚠️ NEEDS SETUP' : '❌ ACTION REQUIRED';
347
+
348
+ console.log('\n Status: ' + statusColor(statusText));
349
+
350
+ // Dependencies
351
+ console.log('\n📦 Dependencies (' + output.checks.dependencies.installed + '/' + output.checks.dependencies.total + ')');
352
+ for (const dep of output.checks.dependencies.items) {
353
+ const icon = dep.installed ? colors.green('✅') : colors.yellow('○');
354
+ const version = dep.version ? colors.gray(`v${dep.version}`) : colors.red('not installed');
355
+ console.log(` ${icon} ${dep.name} ${version}`);
356
+ }
357
+
358
+ // CLI Tools
359
+ console.log('\n🔧 CLI Tools (' + output.checks.cliTools.available + '/' + output.checks.cliTools.total + ')');
360
+ for (const tool of output.checks.cliTools.items) {
361
+ const icon = tool.installed ? colors.green('✅') : colors.yellow('○');
362
+ const version = tool.version ? colors.gray(`(${tool.version})`) : colors.red('not available');
363
+ console.log(` ${icon} ${tool.name} - ${tool.description} ${version}`);
364
+ }
365
+
366
+ // Native binaries
367
+ console.log('\n⚡ Native Binaries');
368
+ if (output.checks.nativeBinaries.status === 'native') {
369
+ console.log(' ' + colors.green('✅ Native mode (fastest)'));
370
+ } else {
371
+ console.log(' ' + colors.yellow('○ CLI mode (falls back via npx)'));
372
+ if (output.checks.nativeBinaries.reason) {
373
+ console.log(' ' + colors.gray(output.checks.nativeBinaries.reason));
374
+ }
375
+ }
376
+
377
+ // Config
378
+ console.log('\n⚙️ Config');
379
+ if (output.checks.config.exists) {
380
+ console.log(' ' + colors.green('✅ Config file found'));
381
+ if (output.checks.config.optimizations.length > 0) {
382
+ console.log(' ' + colors.gray('Optimizations: ' + output.checks.config.optimizations.join(', ')));
383
+ }
384
+ } else {
385
+ console.log(' ' + colors.yellow('○ No config file (optional)'));
386
+ }
387
+
388
+ // Action items
389
+ if (output.actionItems.length > 0) {
390
+ console.log('\n' + colors.gray('─'.repeat(55)));
391
+ console.log('📋 Action Items\n');
392
+
393
+ for (const item of output.actionItems) {
394
+ const priorityColor = item.priority === 'critical' ? colors.red :
395
+ item.priority === 'high' ? colors.yellow :
396
+ item.priority === 'medium' ? colors.blue : colors.gray;
397
+
398
+ console.log(` [${priorityColor(item.priority.toUpperCase())}] ${item.action}`);
399
+ console.log(` ${colors.gray(item.reason)}`);
400
+ if (item.command) {
401
+ console.log(` ${colors.green(item.command)}`);
402
+ }
403
+ console.log();
404
+ }
405
+ }
406
+
407
+ // Quick install
408
+ if (output.installCommands.deps || output.installCommands.cliTools) {
409
+ console.log(colors.gray('─'.repeat(55)));
410
+ console.log('\n🚀 Quick Install\n');
411
+
412
+ if (output.installCommands.deps) {
413
+ console.log(' ' + colors.cyan('Dependencies:'));
414
+ console.log(' ' + colors.green(output.installCommands.deps));
415
+ }
416
+
417
+ if (output.installCommands.cliTools) {
418
+ console.log('\n ' + colors.cyan('CLI Tools:'));
419
+ console.log(' ' + colors.green(output.installCommands.cliTools));
420
+ }
421
+ }
422
+
423
+ console.log('\n' + colors.blue('═'.repeat(55)));
424
+ console.log(colors.gray(' Run with: bunx @hung319/opencode-hive doctor'));
425
+ console.log(colors.blue('═'.repeat(55)) + '\n');
426
+ }
427
+
428
+ // ============================================================================
429
+ // Main
430
+ // ============================================================================
431
+
432
+ const output = runDoctor();
433
+ printDoctor(output);
434
+
435
+ // Exit with appropriate code
436
+ process.exit(output.status === 'ready' ? 0 : 1);