hone-ai 0.14.0 → 0.15.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 CHANGED
@@ -1,9 +1,17 @@
1
- # hone
1
+ # hone-ai
2
2
 
3
3
  **AI Coding Agent Orchestrator** — Automatically implement features from requirements using AI agents.
4
4
 
5
5
  Transform feature ideas into working code through autonomous development with human oversight.
6
6
 
7
+ ## Why
8
+
9
+ When working on long running tasks with agents, their context window fills up and the performance degrades. To mitigate this, hone-ai provides a solution starting each new iteration with a fresh context window just passing in a summary of the progress made so far on the specific PRD, repository architecture and gotchas, and any other relevant information.
10
+
11
+ Everything else is stripped away, leaving only the essential information needed for the next iteration. This approach helps maintain optimal performance and reduces the likelihood of context drift.
12
+
13
+ It's a surprisingly powerful process.
14
+
7
15
  ## Quick Start
8
16
 
9
17
  1. **Install hone**
@@ -12,6 +20,8 @@ Transform feature ideas into working code through autonomous development with hu
12
20
  npm install -g hone-ai
13
21
  # or
14
22
  bun add -g hone-ai
23
+ # or
24
+ # download binary or build from source, instructions below
15
25
  ```
16
26
 
17
27
  2. **Install an AI agent** ([OpenCode](https://opencode.ai) or [Claude Code](https://docs.anthropic.com/claude/docs/claude-code))
@@ -27,7 +37,7 @@ That's it! You're ready to use hone.
27
37
  ## Common Workflow
28
38
 
29
39
  ```bash
30
- # 1. Generate project documentation (if no AGENTS.md exists)
40
+ # 1. Generate project documentation (if no AGENTS.md exists). A one time thing.
31
41
  hone agents-md
32
42
 
33
43
  # 2. Create a PRD from your feature description
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hone-ai",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "description": "AI coding agent orchestrator - orchestrate AI agents to implement features based on PRDs",
5
5
  "keywords": [
6
6
  "ai",
@@ -12,7 +12,7 @@ import {
12
12
  } from './config'
13
13
  import { readFile, writeFile, mkdir } from 'fs/promises'
14
14
  import { join } from 'path'
15
- import { existsSync } from 'fs'
15
+ import { existsSync, readFileSync } from 'fs'
16
16
  import { AgentClient } from './agent-client'
17
17
  import { log, logError, logVerbose, logVerboseError } from './logger'
18
18
 
@@ -424,12 +424,103 @@ async function executeParallelScanning(
424
424
  return scanResults
425
425
  }
426
426
 
427
+ /**
428
+ * Generate project-specific feedback commands based on package.json and project files
429
+ */
430
+ function generateFeedbackContent(projectPath: string, analysis: ProjectAnalysis): string {
431
+ const feedbackCommands: string[] = []
432
+
433
+ // Read package.json to get actual project scripts
434
+ let packageJsonScripts: Record<string, string> = {}
435
+ try {
436
+ const packageJsonPath = join(projectPath, 'package.json')
437
+ if (existsSync(packageJsonPath)) {
438
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'))
439
+ packageJsonScripts = packageJson.scripts || {}
440
+ }
441
+ } catch (error) {
442
+ logVerbose('[AgentsMd] Could not read package.json scripts')
443
+ }
444
+
445
+ // Unit tests - use actual package.json scripts or detected framework
446
+ if (packageJsonScripts.test) {
447
+ feedbackCommands.push(`**Unit Tests:** \`npm run test\` or \`${packageJsonScripts.test}\``)
448
+ } else if (analysis.testingFrameworks.some(fw => fw.toLowerCase().includes('jest'))) {
449
+ feedbackCommands.push('**Unit Tests:** `npm test` or `jest`')
450
+ } else if (analysis.testingFrameworks.some(fw => fw.toLowerCase().includes('pytest'))) {
451
+ feedbackCommands.push('**Unit Tests:** `pytest`')
452
+ } else if (analysis.testingFrameworks.some(fw => fw.toLowerCase().includes('bun'))) {
453
+ feedbackCommands.push('**Unit Tests:** `bun test`')
454
+ } else {
455
+ feedbackCommands.push('**Unit Tests:** `bun test`')
456
+ }
457
+
458
+ // Code formatting - use actual package.json scripts if available
459
+ if (packageJsonScripts.format) {
460
+ feedbackCommands.push(
461
+ `**Code Formatting:** \`npm run format\` or \`${packageJsonScripts.format}\``
462
+ )
463
+ } else if (
464
+ analysis.languages.some(
465
+ lang => lang.toLowerCase().includes('typescript') || lang.toLowerCase().includes('javascript')
466
+ )
467
+ ) {
468
+ feedbackCommands.push('**Code Formatting:** `prettier --write "**/*.{ts,tsx,js,jsx}"`')
469
+ }
470
+
471
+ // Code linting - check for lint script or eslint
472
+ if (packageJsonScripts.lint) {
473
+ feedbackCommands.push(`**Code Linting:** \`npm run lint\` or \`${packageJsonScripts.lint}\``)
474
+ } else if (
475
+ analysis.languages.some(
476
+ lang => lang.toLowerCase().includes('typescript') || lang.toLowerCase().includes('javascript')
477
+ )
478
+ ) {
479
+ feedbackCommands.push('**Code Linting:** `eslint . --fix`')
480
+ }
481
+
482
+ // YAML formatting and linting from package.json scripts
483
+ if (packageJsonScripts['format:yaml']) {
484
+ feedbackCommands.push(
485
+ `**YAML Formatting:** \`npm run format:yaml\` or \`${packageJsonScripts['format:yaml']}\``
486
+ )
487
+ }
488
+ if (packageJsonScripts['lint:yaml']) {
489
+ feedbackCommands.push(
490
+ `**YAML Linting:** \`npm run lint:yaml\` or \`${packageJsonScripts['lint:yaml']}\``
491
+ )
492
+ }
493
+
494
+ // Build command - use actual package.json scripts or detected build systems
495
+ if (packageJsonScripts.build) {
496
+ feedbackCommands.push(`**Build:** \`npm run build\` or \`${packageJsonScripts.build}\``)
497
+ } else if (analysis.buildSystems.length > 0) {
498
+ const buildSystems = analysis.buildSystems.map(sys => sys.toLowerCase())
499
+ if (buildSystems.some(sys => sys.includes('bun'))) {
500
+ feedbackCommands.push('**Build:** `bun run build`')
501
+ } else if (buildSystems.some(sys => sys.includes('npm') || sys.includes('yarn'))) {
502
+ feedbackCommands.push('**Build:** `npm run build` or `yarn build`')
503
+ } else if (buildSystems.some(sys => sys.includes('maven'))) {
504
+ feedbackCommands.push('**Build:** `mvn clean compile`')
505
+ } else if (buildSystems.some(sys => sys.includes('gradle'))) {
506
+ feedbackCommands.push('**Build:** `./gradlew build`')
507
+ }
508
+ }
509
+
510
+ return `Run these commands to validate your changes before committing:
511
+
512
+ ${feedbackCommands.join('\n\n')}
513
+
514
+ These commands are project-specific based on the configured scripts and tooling.`
515
+ }
516
+
427
517
  /**
428
518
  * Create adaptive template sections based on discovered tech stack
429
519
  */
430
520
  function createTemplateSections(
431
521
  scanResults: Record<keyof typeof DISCOVERY_PROMPTS, string>,
432
- analysis: ProjectAnalysis
522
+ analysis: ProjectAnalysis,
523
+ projectPath: string
433
524
  ): TemplateSection[] {
434
525
  const sections: TemplateSection[] = []
435
526
 
@@ -500,6 +591,14 @@ function createTemplateSections(
500
591
  })
501
592
  }
502
593
 
594
+ // Add feedback section inline at the top with project-specific commands
595
+ sections.push({
596
+ title: 'Feedback Instructions',
597
+ content: generateFeedbackContent(projectPath, analysis),
598
+ priority: 0, // Highest priority to appear at top
599
+ detailFile: undefined, // Force inline, never create separate file
600
+ })
601
+
503
602
  // Sort by priority
504
603
  return sections.sort((a, b) => a.priority - b.priority)
505
604
  }
@@ -543,16 +642,25 @@ ${section.content}
543
642
  )
544
643
  }
545
644
 
546
- // Compact version with references to ${AGENTS_DOCS_DIR}/ files
645
+ // Compact version with references to ${AGENTS_DOCS_DIR}/ files, but keep inline sections inline
547
646
  const compactSections = sections
548
- .map(
549
- section => `## ${section.title}
647
+ .map(section => {
648
+ // If section has no detailFile, render it inline (like Feedback Instructions)
649
+ if (!section.detailFile) {
650
+ return `## ${section.title}
651
+
652
+ ${section.content}
653
+ `
654
+ }
655
+
656
+ // Otherwise, use compact format with reference to detail file
657
+ return `## ${section.title}
550
658
 
551
659
  ${getFirstSentence(section.content)}
552
660
 
553
661
  See [@${AGENTS_DOCS_DIR}/${section.detailFile}](${AGENTS_DOCS_DIR}/${section.detailFile}) for detailed information.
554
662
  `
555
- )
663
+ })
556
664
  .join('\n')
557
665
 
558
666
  return (
@@ -680,7 +788,7 @@ async function generateContent(
680
788
  log('-'.repeat(80))
681
789
 
682
790
  // Create adaptive template sections based on discovered tech stack
683
- const sections = createTemplateSections(scanResults, analysis)
791
+ const sections = createTemplateSections(scanResults, analysis, projectPath)
684
792
 
685
793
  // Generate initial content to check line count
686
794
  const fullContent = generateCompactContent(sections, false)
package/src/prompt.ts CHANGED
@@ -262,7 +262,7 @@ ${reviewFeedback || 'No review feedback provided (review was skipped or approved
262
262
  Next Task: <next-task-id> or "All tasks complete"
263
263
  \`\`\`
264
264
 
265
- 5. **Update AGENTS.md** (if learnings exist)
265
+ 5. **Update AGENTS.md file**
266
266
  - Add useful learnings and gotchas under appropriate heading
267
267
  - Be terse - only add truly useful info that future agents need
268
268
  - Don't duplicate existing info