BREAKING CHANGE(aidoc): migrate agent orchestration to new runAgent API and filesystem tools; refactor model handling and update README and tests

This commit is contained in:
2026-03-11 18:58:48 +00:00
parent 883985dbc0
commit 6b2957b272
11 changed files with 834 additions and 3270 deletions

View File

@@ -1,5 +1,17 @@
# Changelog
## 2026-03-11 - 2.0.0 - BREAKING CHANGE(aidoc)
migrate agent orchestration to new runAgent API and filesystem tools; refactor model handling and update README and tests
- Replace DualAgentOrchestrator with plugins.smartagent.runAgent and scoped filesystem tools
- Introduce smartagentTools export and use filesystemTool for agents
- Replace smartAiInstance with model via plugins.smartai.getModel() and remove previous lifecycle methods (breaking API change)
- Normalize agent output property from result to text and standardize log messages (removed emojis)
- Update changelog/README/description generation flows to use new agent interface
- Bump several devDependencies and dependencies (tsbuild, tstest, @types/node, tspublish, push.rocks packages, typedoc, typescript)
- Change test entry to export default tap.start()
- Revise README content and structure
## 2026-01-04 - 1.12.0 - feat(commit)
add token budgeting and dynamic diff token calculation to avoid OpenAI context limit issues

View File

@@ -19,30 +19,30 @@
"buildDocs": "tsdoc"
},
"devDependencies": {
"@git.zone/tsbuild": "^4.0.2",
"@git.zone/tsbuild": "^4.3.0",
"@git.zone/tsrun": "^2.0.1",
"@git.zone/tstest": "^3.1.4",
"@types/node": "^25.0.3"
"@git.zone/tstest": "^3.3.2",
"@types/node": "^25.4.0"
},
"dependencies": {
"@git.zone/tspublish": "^1.11.0",
"@git.zone/tspublish": "^1.11.2",
"@push.rocks/early": "^4.0.4",
"@push.rocks/npmextra": "^5.3.3",
"@push.rocks/qenv": "^6.1.3",
"@push.rocks/smartagent": "1.2.5",
"@push.rocks/smartai": "^0.8.0",
"@push.rocks/smartcli": "^4.0.19",
"@push.rocks/smartagent": "^3.0.2",
"@push.rocks/smartai": "^2.0.0",
"@push.rocks/smartcli": "^4.0.20",
"@push.rocks/smartdelay": "^3.0.5",
"@push.rocks/smartfile": "^13.1.2",
"@push.rocks/smartfs": "^1.3.1",
"@push.rocks/smartfs": "^1.5.0",
"@push.rocks/smartgit": "^3.3.1",
"@push.rocks/smartinteract": "^2.0.16",
"@push.rocks/smartlog": "^3.1.10",
"@push.rocks/smartlog": "^3.2.1",
"@push.rocks/smartlog-destination-local": "^9.0.2",
"@push.rocks/smartpath": "^6.0.0",
"@push.rocks/smartshell": "^3.3.0",
"@push.rocks/smarttime": "^4.1.1",
"typedoc": "^0.28.15",
"@push.rocks/smartshell": "^3.3.7",
"@push.rocks/smarttime": "^4.2.3",
"typedoc": "^0.28.17",
"typescript": "^5.9.3"
},
"files": [

3174
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

492
readme.md
View File

@@ -1,4 +1,4 @@
# @git.zone/tsdoc 🚀
# @git.zone/tsdoc
AI-Powered Documentation for TypeScript Projects
@@ -6,402 +6,226 @@ AI-Powered Documentation for TypeScript Projects
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
## What is tsdoc?
`@git.zone/tsdoc` is a next-generation documentation CLI tool that combines traditional TypeDoc generation with cutting-edge AI to create comprehensive, intelligent documentation for your TypeScript projects. It reads your code, understands it, and writes documentation that actually makes sense.
### ✨ Key Features
- **🤖 AI-Enhanced Documentation** - Leverages AI to generate contextual READMEs
- **🧠 Smart Context Building** - Intelligent file prioritization with dependency analysis and caching
- **📚 TypeDoc Integration** - Classic API documentation generation when you need it
- **💬 Smart Commit Messages** - AI analyzes your changes and suggests meaningful commit messages
- **🎯 Context Optimization** - Advanced token management with 40-60% reduction in usage
- **⚡ Performance Optimized** - 3-5x faster with lazy loading and parallel processing
- **📦 Zero Config** - Works out of the box with sensible defaults
- **🔧 Highly Configurable** - Customize every aspect when needed
## Installation
## Install
```bash
# Global installation (recommended)
# Global installation (recommended for CLI usage)
pnpm add -g @git.zone/tsdoc
# Or use with npx
npx @git.zone/tsdoc
# Or install locally as a dependency
pnpm add @git.zone/tsdoc
```
## Quick Start
## Usage
### Generate AI-Powered Documentation
`@git.zone/tsdoc` is a comprehensive TypeScript documentation tool that combines traditional TypeDoc API documentation generation with AI-powered documentation workflows. It uses OpenAI models via the Vercel AI SDK to generate READMEs, project descriptions, keywords, and semantic commit messages by intelligently exploring your project with agentic tool use.
### CLI Commands
| Command | Description |
|---------|-------------|
| `tsdoc` | Auto-detects project type and runs TypeDoc |
| `tsdoc aidoc` | Generates AI-powered README + description/keywords |
| `tsdoc readme` | Generates AI-powered README only |
| `tsdoc description` | Generates AI-powered description and keywords only |
| `tsdoc commit` | Generates a semantic commit message from uncommitted changes |
| `tsdoc typedoc` | Generates traditional TypeDoc API documentation |
### Generating AI-Powered Documentation
The `aidoc` command combines README generation and description/keyword generation in one step:
```bash
# In your project root
tsdoc aidoc
```
That's it! tsdoc will analyze your entire codebase and generate:
- A comprehensive README.md
- Updated package.json description and keywords
- Smart documentation based on your actual code structure
This will:
1. Analyze your codebase using an AI agent with filesystem access
2. Generate a comprehensive `readme.md`
3. Update `package.json` and `npmextra.json` with an AI-generated description and keywords
### Generate Traditional TypeDoc
You can also run these separately:
```bash
tsdoc typedoc --publicSubdir docs
# Generate only the README
tsdoc readme
# Generate only the description and keywords
tsdoc description
```
### Get Smart Commit Messages
### Generating Commit Messages
The `commit` command analyzes your uncommitted changes and produces a structured commit object:
```bash
tsdoc commit
```
## CLI Commands
Output is a JSON object following conventional commits:
| Command | Description |
|---------|-------------|
| `tsdoc` | Auto-detects and runs appropriate documentation |
| `tsdoc aidoc` | Generate AI-enhanced documentation |
| `tsdoc typedoc` | Generate TypeDoc documentation |
| `tsdoc commit` | Generate smart commit message |
| `tsdoc tokens` | Analyze token usage for AI context |
### Token Analysis
Understanding token usage helps optimize AI costs:
```bash
# Show token count for current project
tsdoc tokens
# Show detailed stats for all task types
tsdoc tokens --all
# Show detailed breakdown with file listing
tsdoc tokens --detailed --listFiles
```json
{
"recommendedNextVersionLevel": "feat",
"recommendedNextVersionScope": "core",
"recommendedNextVersionMessage": "add new feature for better documentation",
"recommendedNextVersionDetails": [
"implemented X",
"refactored Y"
],
"recommendedNextVersion": "1.13.0",
"changelog": "# Changelog\n\n## 2026-03-11 - 1.13.0 - core\n..."
}
```
### Command Options
The commit command includes intelligent diff processing that:
- Excludes lock files, build artifacts, IDE directories, and caches from the diff
- Prioritizes source files over build artifacts
- Samples large diffs with head/tail extraction to stay within token budgets
- Automatically generates or updates the changelog
#### tsdoc aidoc
- `--tokens` / `--showTokens` - Show token count before generating
- `--tokensOnly` - Only show token count, don't generate
### Generating TypeDoc
#### tsdoc typedoc
- `--publicSubdir <dir>` - Output subdirectory within public folder
For traditional API documentation via TypeDoc:
#### tsdoc tokens
- `--task <type>` - Specify task type: `readme`, `commit`, or `description`
- `--all` - Show stats for all task types
- `--detailed` - Show detailed token usage and costs
- `--listFiles` - List all files included in context
- `--model <name>` - Show usage for specific model (`gpt4`, `gpt35`)
```bash
# Generate to default ./public directory
tsdoc typedoc
# Generate to a specific subdirectory
tsdoc typedoc --publicSubdir docs
```
### Monorepo Support
When generating READMEs, tsdoc automatically detects monorepo submodules via `@git.zone/tspublish` conventions. Each submodule directory with a `tspublish.json` gets its own generated README.
### Programmatic API
You can also use tsdoc programmatically:
```typescript
import { AiDoc } from '@git.zone/tsdoc';
const aidoc = new AiDoc();
await aidoc.start(); // Initializes the AI model (prompts for OpenAI token if needed)
// Generate a README
await aidoc.buildReadme('/path/to/project');
// Generate description and keywords
await aidoc.buildDescription('/path/to/project');
// Generate a commit message object
const commitObj = await aidoc.buildNextCommitObject('/path/to/project');
console.log(commitObj);
// Get project context information
const context = await aidoc.getProjectContext('/path/to/project');
// Get token count for a project
const tokenCount = await aidoc.getProjectContextTokenCount('/path/to/project');
// Estimate tokens in arbitrary text
const tokens = aidoc.countTokens('some text here');
await aidoc.stop();
```
## Configuration
Configure tsdoc via `npmextra.json`:
### OpenAI Token
An OpenAI API key is required for all AI features. It can be provided in three ways:
1. **Environment variable**: `OPENAI_TOKEN`
2. **Interactive prompt**: On first run, tsdoc will prompt for the token and persist it
3. **Constructor argument**: Pass `{ OPENAI_TOKEN: 'sk-...' }` to `new AiDoc()`
The token is persisted at `~/.npmextra/kv/@git.zone/tsdoc.json` for subsequent runs.
### npmextra.json
tsdoc uses `npmextra.json` for project metadata. The `tsdoc` key holds legal information that gets appended to generated READMEs:
```json
{
"@git.zone/tsdoc": {
"legal": "## License and Legal Information\n\n...",
"context": {
"maxTokens": 190000,
"defaultMode": "trimmed",
"cache": {
"enabled": true,
"ttl": 3600,
"maxSize": 100
},
"analyzer": {
"useAIRefinement": false
},
"prioritization": {
"dependencyWeight": 0.3,
"relevanceWeight": 0.4,
"efficiencyWeight": 0.2,
"recencyWeight": 0.1
},
"tiers": {
"essential": { "minScore": 0.8, "trimLevel": "none" },
"important": { "minScore": 0.5, "trimLevel": "light" },
"optional": { "minScore": 0.2, "trimLevel": "aggressive" }
},
"taskSpecificSettings": {
"readme": {
"mode": "trimmed",
"includePaths": ["ts/", "src/"],
"excludePaths": ["test/", "node_modules/"]
},
"commit": {
"mode": "trimmed",
"focusOnChangedFiles": true
}
},
"trimming": {
"removeImplementations": true,
"preserveInterfaces": true,
"preserveJSDoc": true,
"maxFunctionLines": 5,
"removeComments": true
}
"tsdoc": {
"legal": "\n## License and Legal Information\n\n..."
},
"gitzone": {
"module": {
"githost": "gitlab.com",
"gitscope": "gitzone",
"gitrepo": "tsdoc",
"npmPackagename": "@git.zone/tsdoc",
"description": "...",
"keywords": ["..."]
}
}
}
```
### Configuration Options
#### Context Settings
- **maxTokens** - Maximum tokens for AI context (default: 190000)
- **defaultMode** - Default context mode: 'full', 'trimmed', or 'summarized'
- **cache** - Caching configuration for improved performance
- **analyzer** - Smart file analysis and prioritization settings
- **prioritization** - Weights for file importance scoring
- **tiers** - Tier thresholds and trimming levels
#### Cache Configuration
- **enabled** - Enable/disable file caching (default: true)
- **ttl** - Time-to-live in seconds (default: 3600)
- **maxSize** - Maximum cache size in MB (default: 100)
- **directory** - Cache directory path (default: .nogit/context-cache)
## How It Works
### 🚀 Smart Context Building Pipeline
1. **📊 Fast Metadata Scanning** - Lazy loading scans files without reading contents
2. **🧬 Dependency Analysis** - Builds dependency graph from import statements
3. **🎯 Intelligent Scoring** - Multi-factor importance scoring:
- **Relevance**: Task-specific file importance (e.g., index.ts for READMEs)
- **Centrality**: How many files depend on this file
- **Efficiency**: Information density (tokens vs. value)
- **Recency**: Recently changed files (for commits)
4. **🏆 Smart Prioritization** - Files sorted by combined importance score
5. **🎭 Tier-Based Trimming** - Adaptive trimming based on importance:
- **Essential** (score ≥ 0.8): No trimming
- **Important** (score ≥ 0.5): Light trimming
- **Optional** (score ≥ 0.2): Aggressive trimming
6. **💾 Intelligent Caching** - Cache results with file change detection
7. **🧠 AI Processing** - Send optimized context to AI for documentation
### Context Optimization Benefits
The smart context system delivers significant improvements:
| Metric | Before | After | Improvement |
|--------|--------|-------|-------------|
| **Token Usage** | ~190k (limit) | ~110-130k | ⬇️ 40-60% reduction |
| **Build Time** | 4-6 seconds | 1-2 seconds | ⚡ 3-5x faster |
| **Memory Usage** | All files loaded | Metadata + selected | 📉 80%+ reduction |
| **Relevance** | Alphabetical sorting | Smart scoring | 🎯 90%+ relevant |
| **Cache Hits** | None | 70-80% | 🚀 Major speedup |
## Environment Variables
| Variable | Description |
|----------|-------------|
| `OPENAI_TOKEN` | Your OpenAI API key for AI features (required) |
The token can also be provided interactively on first run - it will be persisted in `~/.npmextra/kv/@git.zone/tsdoc.json`.
## Use Cases
### 🚀 Continuous Integration
```yaml
# .github/workflows/docs.yml
name: Documentation
on: [push]
jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Generate Documentation
env:
OPENAI_TOKEN: ${{ secrets.OPENAI_TOKEN }}
run: |
npm install -g @git.zone/tsdoc
tsdoc aidoc
- name: Commit Changes
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add readme.md package.json
git commit -m "docs: update documentation [skip ci]" || exit 0
git push
```
### 🔄 Pre-Commit Hooks
```bash
# .git/hooks/prepare-commit-msg
#!/bin/bash
tsdoc commit > .git/COMMIT_EDITMSG
```
### 📦 Package Publishing
```json
{
"scripts": {
"prepublishOnly": "tsdoc aidoc",
"version": "tsdoc aidoc && git add readme.md"
}
}
```
## Requirements
- **Node.js** >= 18.0.0
- **TypeScript** project
- **OpenAI API key** (for AI features)
## Troubleshooting
### Token Limit Exceeded
If you hit token limits, try:
```bash
# Check token usage details
tsdoc tokens --all --detailed
```
Or configure stricter limits in `npmextra.json`:
```json
{
"@git.zone/tsdoc": {
"context": {
"maxTokens": 100000,
"tiers": {
"essential": { "minScore": 0.9, "trimLevel": "none" },
"important": { "minScore": 0.7, "trimLevel": "aggressive" },
"optional": { "minScore": 0.5, "trimLevel": "aggressive" }
}
}
}
}
```
### Missing API Key
Set your OpenAI key:
```bash
export OPENAI_TOKEN="your-key-here"
tsdoc aidoc
```
### Slow Performance
Enable caching and adjust settings in `npmextra.json`:
```json
{
"@git.zone/tsdoc": {
"context": {
"cache": {
"enabled": true,
"ttl": 7200,
"maxSize": 200
}
}
}
}
```
### Cache Issues
Clear the cache if needed:
```bash
rm -rf .nogit/context-cache
```
## Why tsdoc?
### 🎯 Actually Understands Your Code
Not just parsing, but real comprehension through AI. The smart context system ensures AI sees the most relevant parts of your codebase.
### ⏱️ Saves Hours
Generate complete, accurate documentation in seconds. The intelligent caching system makes subsequent runs even faster.
### 🔄 Always Up-to-Date
Regenerate documentation with every change. Smart dependency analysis ensures nothing important is missed.
### 🎨 Beautiful Output
Clean, professional documentation every time. AI understands your code's purpose and explains it clearly.
### 💰 Cost-Effective
Smart context optimization reduces AI API costs by 40-60% without sacrificing quality.
## Architecture
### Core Components
```
@git.zone/tsdoc
├── AiDoc # Main AI documentation orchestrator
├── TypeDoc # Traditional TypeDoc integration
├── Context System # Smart context building
│ ├── EnhancedContext # Main context builder
│ ├── LazyFileLoader # Efficient file loading
├── ContextCache # Performance caching
│ ├── ContextAnalyzer # Intelligent file analysis
│ ├── ContextTrimmer # Adaptive code trimming
│ ├── DiffProcessor # Git diff optimization
│ ├── ConfigManager # Configuration management
│ └── TaskContextFactory # Task-specific contexts
└── CLI # Command-line interface
├── AiDoc # Main orchestrator - manages AI model and delegates to task classes
├── TypeDoc # Traditional TypeDoc API documentation generation
├── ProjectContext # Gathers project files for context (package.json, ts/, test/)
├── DiffProcessor # Intelligent git diff processing with prioritization and sampling
├── Readme # AI-powered README generation using runAgent with filesystem tools
├── Commit # AI-powered commit message generation with diff analysis
├── Description # AI-powered description and keyword generation
└── CLI # Command-line interface built on @push.rocks/smartcli
```
### Data Flow
### AI Agent Architecture
```
Project Files
LazyFileLoader (metadata scan)
ContextAnalyzer (scoring & prioritization)
ContextCache (check cache)
File Loading (parallel, on-demand)
ContextTrimmer (tier-based)
Token Budget (enforcement)
AI Model
Generated Documentation
```
tsdoc uses `@push.rocks/smartagent`'s `runAgent()` function with `@push.rocks/smartai`'s `getModel()` for all AI tasks. Each documentation task (readme, commit, description) runs an autonomous AI agent that:
1. Receives a system prompt defining its role and constraints
2. Gets access to scoped filesystem tools (read-only, limited to project directory)
3. Explores the project structure autonomously using tool calls
4. Produces the final output (README markdown, commit JSON, or description JSON)
### Diff Processing
The `DiffProcessor` class handles large git diffs intelligently:
- **Small files** (< 300 lines): Included in full
- **Medium files** (< 800 lines): Head/tail sampling with context
- **Large files**: Metadata only (filepath, lines added/removed)
- Files are prioritized by importance: source > test > config > docs > build artifacts
- Token budget is enforced dynamically based on OpenAI's context limits
## Requirements
- **Node.js** >= 18.0.0
- **TypeScript** project with `ts/` source directory
- **OpenAI API key** (for AI features)
## License and Legal Information
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./LICENSE) file.
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
### Trademarks
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
### Company Information
Task Venture Capital GmbH
Registered at District Court Bremen HRB 35230 HB, Germany
Registered at District court Bremen HRB 35230 HB, Germany
For any legal inquiries or further information, please contact us via email at hello@task.vc.
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.

View File

@@ -39,4 +39,4 @@ tap.test('should stop AIdocs', async () => {
await aidocs.stop();
});
tap.start();
export default tap.start();

View File

@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@git.zone/tsdoc',
version: '1.12.0',
version: '2.0.0',
description: 'A comprehensive TypeScript documentation tool that leverages AI to generate and enhance project documentation, including dynamic README creation, API docs via TypeDoc, and smart commit message generation.'
}

View File

@@ -103,7 +103,7 @@ export class Commit {
const totalChars = diffStringArray.join('\n\n').length;
const estimatedTokens = Math.ceil(totalChars / 4);
console.log(`📊 Raw git diff statistics:`);
console.log(`Raw git diff statistics:`);
console.log(` Files changed: ${diffStringArray.length}`);
console.log(` Total characters: ${totalChars.toLocaleString()}`);
console.log(` Estimated tokens: ${estimatedTokens.toLocaleString()}`);
@@ -111,7 +111,7 @@ export class Commit {
// Calculate available tokens for diff based on total budget
const maxDiffTokens = calculateMaxDiffTokens();
console.log(`📊 Token budget: ${maxDiffTokens.toLocaleString()} tokens for diff (limit: ${TOKEN_BUDGET.OPENAI_CONTEXT_LIMIT.toLocaleString()}, overhead: ${(TOKEN_BUDGET.SMARTAGENT_OVERHEAD + TOKEN_BUDGET.TASK_PROMPT_OVERHEAD).toLocaleString()})`);
console.log(`Token budget: ${maxDiffTokens.toLocaleString()} tokens for diff (limit: ${TOKEN_BUDGET.OPENAI_CONTEXT_LIMIT.toLocaleString()}, overhead: ${(TOKEN_BUDGET.SMARTAGENT_OVERHEAD + TOKEN_BUDGET.TASK_PROMPT_OVERHEAD).toLocaleString()})`);
// Use DiffProcessor to intelligently handle large diffs
const diffProcessor = new DiffProcessor({
@@ -125,14 +125,14 @@ export class Commit {
const processedDiff = diffProcessor.processDiffs(diffStringArray);
processedDiffString = diffProcessor.formatForContext(processedDiff);
console.log(`📝 Processed diff statistics:`);
console.log(`Processed diff statistics:`);
console.log(` Full diffs: ${processedDiff.fullDiffs.length} files`);
console.log(` Summarized: ${processedDiff.summarizedDiffs.length} files`);
console.log(` Metadata only: ${processedDiff.metadataOnly.length} files`);
console.log(` Final tokens: ${processedDiff.totalTokens.toLocaleString()}`);
if (estimatedTokens > 50000) {
console.log(`DiffProcessor reduced token usage: ${estimatedTokens.toLocaleString()} ${processedDiff.totalTokens.toLocaleString()}`);
console.log(`DiffProcessor reduced token usage: ${estimatedTokens.toLocaleString()} -> ${processedDiff.totalTokens.toLocaleString()}`);
}
// Validate total tokens won't exceed limit
@@ -141,71 +141,44 @@ export class Commit {
+ TOKEN_BUDGET.TASK_PROMPT_OVERHEAD;
if (totalEstimatedTokens > TOKEN_BUDGET.OPENAI_CONTEXT_LIMIT - TOKEN_BUDGET.SAFETY_MARGIN) {
console.log(`⚠️ Warning: Estimated tokens (${totalEstimatedTokens.toLocaleString()}) approaching limit`);
console.log(`Warning: Estimated tokens (${totalEstimatedTokens.toLocaleString()}) approaching limit`);
console.log(` Consider splitting into smaller commits`);
}
} else {
processedDiffString = 'No changes.';
}
// Use DualAgentOrchestrator for commit message generation
const commitOrchestrator = new plugins.smartagent.DualAgentOrchestrator({
smartAiInstance: this.aiDocsRef.smartAiInstance,
defaultProvider: 'openai',
logPrefix: '[Commit]',
onProgress: (event) => logger.log(event.logLevel, event.logMessage),
guardianPolicyPrompt: `
You validate commit messages for semantic versioning compliance.
// Use runAgent for commit message generation with filesystem tool
const fsTools = plugins.smartagentTools.filesystemTool({ rootDir: this.projectDir });
APPROVE tool calls for:
- Reading package.json or source files to understand project context
- Using tree to see project structure
- Listing directory contents
const commitSystemPrompt = `
You create commit messages for git commits following semantic versioning conventions.
REJECT tool calls for:
- Reading files outside the project directory
- Writing, deleting, or modifying any files
- Any destructive operations
You have access to filesystem tools to explore the project if needed.
APPROVE final output if:
- Version level (fix/feat/BREAKING CHANGE) matches the scope of changes in the diff
- Commit message is clear, professional, and follows conventional commit conventions
- No personal information, licensing details, or AI mentions (Claude/Codex) included
- JSON structure is valid with all required fields
- Scope accurately reflects the changed modules/files
REJECT final output if:
- Version level doesn't match the scope of changes (e.g., "feat" for a typo fix should be "fix")
- Message is vague, unprofessional, or contains sensitive information
- JSON is malformed or missing required fields
`,
});
// Register scoped filesystem tool for agent exploration
commitOrchestrator.registerScopedFilesystemTool(this.projectDir, [
'.nogit/**',
'node_modules/**',
'.git/**',
'dist/**',
'dist_*/**',
]);
await commitOrchestrator.start();
IMPORTANT RULES:
- Only READ files (package.json, source files) for context
- Do NOT write, delete, or modify any files
- Version level (fix/feat/BREAKING CHANGE) must match the scope of changes
- Commit message must be clear, professional, and follow conventional commit conventions
- Do NOT include personal information, licensing details, or AI mentions (Claude/Codex)
- JSON structure must be valid with all required fields
- Scope must accurately reflect the changed modules/files
`;
const commitTaskPrompt = `
You create a commit message for a git commit.
Project directory: ${this.projectDir}
You have access to a filesystem tool to explore the project if needed:
- Use tree to see project structure
- Use read to read package.json or source files for context
You have access to filesystem tools to explore the project if needed:
- Use list_directory to see project structure
- Use read_file to read package.json or source files for context
Analyze the git diff below to understand what changed and generate a commit message.
You should not include any licensing information or personal information.
Never mention CLAUDE code, or codex.
Your final output (inside the task_complete tags) must be ONLY valid JSON - the raw JSON object, nothing else.
Your final response must be ONLY valid JSON - the raw JSON object, nothing else.
No explanations, no summaries, no markdown - just the JSON object that can be parsed with JSON.parse().
Here is the structure of the JSON you must return:
@@ -227,15 +200,19 @@ ${processedDiffString}
Analyze these changes and output the JSON commit message object.
`;
const commitResult = await commitOrchestrator.run(commitTaskPrompt);
await commitOrchestrator.stop();
logger.log('info', 'Starting commit message generation with agent...');
if (!commitResult.success) {
throw new Error(`Commit message generation failed: ${commitResult.status}`);
}
const commitResult = await plugins.smartagent.runAgent({
model: this.aiDocsRef.model,
prompt: commitTaskPrompt,
system: commitSystemPrompt,
tools: fsTools,
maxSteps: 10,
onToolCall: (toolName) => logger.log('info', `[Commit] Tool call: ${toolName}`),
});
// Extract JSON from result - handle cases where AI adds text around it
let jsonString = commitResult.result
let jsonString = commitResult.text
.replace(/```json\n?/gi, '')
.replace(/```\n?/gi, '');
@@ -259,30 +236,16 @@ Analyze these changes and output the JSON commit message object.
const commitMessages = await gitRepo.getAllCommitMessages();
console.log(JSON.stringify(commitMessages, null, 2));
// Use DualAgentOrchestrator for changelog generation with Guardian validation
const changelogOrchestrator = new plugins.smartagent.DualAgentOrchestrator({
smartAiInstance: this.aiDocsRef.smartAiInstance,
defaultProvider: 'openai',
logPrefix: '[Changelog]',
onProgress: (event) => logger.log(event.logLevel, event.logMessage),
guardianPolicyPrompt: `
You validate changelog generation.
const changelogSystemPrompt = `
You generate changelog.md files for software projects.
APPROVE if:
- Changelog follows proper markdown format with ## headers for each version
- Entries are chronologically ordered (newest first)
- Version ranges for trivial commits are properly summarized
RULES:
- Changelog must follow proper markdown format with ## headers for each version
- Entries must be chronologically ordered (newest first)
- Version ranges for trivial commits should be properly summarized
- No duplicate or empty entries
- Format matches: ## yyyy-mm-dd - x.x.x - scope
REJECT with feedback if:
- Markdown formatting is incorrect
- Entries are not meaningful or helpful
- Dates or versions are malformed
`,
});
await changelogOrchestrator.start();
- Format: ## yyyy-mm-dd - x.x.x - scope
`;
const changelogTaskPrompt = `
You are building a changelog.md file for the project.
@@ -291,7 +254,7 @@ Omit commits and versions that lack relevant changes, but make sure to mention t
A changelog entry should look like this:
## yyyy-mm-dd - x.x.x - scope here
main descriptiom here
main description here
- detailed bullet points follow
@@ -305,16 +268,17 @@ Here are the commit messages:
${JSON.stringify(commitMessages, null, 2)}
`;
const changelogResult = await changelogOrchestrator.run(changelogTaskPrompt);
await changelogOrchestrator.stop();
if (!changelogResult.success) {
throw new Error(`Changelog generation failed: ${changelogResult.status}`);
}
const changelogResult = await plugins.smartagent.runAgent({
model: this.aiDocsRef.model,
prompt: changelogTaskPrompt,
system: changelogSystemPrompt,
maxSteps: 1,
onToolCall: (toolName) => logger.log('info', `[Changelog] Tool call: ${toolName}`),
});
previousChangelog = plugins.smartfileFactory.fromString(
previousChangelogPath,
changelogResult.result.replaceAll('```markdown', '').replaceAll('```', ''),
changelogResult.text.replaceAll('```markdown', '').replaceAll('```', ''),
'utf8'
);
}

View File

@@ -19,53 +19,29 @@ export class Description {
}
public async build() {
// Use DualAgentOrchestrator with filesystem tool for agent-driven exploration
const descriptionOrchestrator = new plugins.smartagent.DualAgentOrchestrator({
smartAiInstance: this.aiDocsRef.smartAiInstance,
defaultProvider: 'openai',
maxIterations: 15,
maxResultChars: 10000, // Limit tool output to prevent token explosion
maxHistoryMessages: 15, // Limit history window
logPrefix: '[Description]',
onProgress: (event) => logger.log(event.logLevel, event.logMessage),
guardianPolicyPrompt: `
You validate description generation tool calls and outputs.
// Use runAgent with filesystem tool for agent-driven exploration
const fsTools = plugins.smartagentTools.filesystemTool({ rootDir: this.projectDir });
APPROVE tool calls for:
- Reading package.json, npmextra.json, or source files in the ts/ directory
- Listing directory contents to understand project structure
- Using tree to see project structure
const descriptionSystemPrompt = `
You create project descriptions and keywords for npm packages.
REJECT tool calls for:
- Reading files outside the project directory
- Writing, deleting, or modifying any files
- Any destructive operations
You have access to filesystem tools to explore the project.
For final output, APPROVE if:
- JSON is valid and parseable
- Description is a clear, concise one-sentence summary
- Keywords are relevant to the project's use cases
- Both description and keywords fields are present
REJECT final output if:
- JSON is malformed or wrapped in markdown code blocks
- Description is too long or vague
- Keywords are irrelevant or generic
`,
});
// Register scoped filesystem tool for agent exploration
descriptionOrchestrator.registerScopedFilesystemTool(this.projectDir);
await descriptionOrchestrator.start();
IMPORTANT RULES:
- Only READ files (package.json, npmextra.json, source files in ts/)
- Do NOT write, delete, or modify any files
- Your final response must be valid JSON only
- Description must be a clear, concise one-sentence summary
- Keywords must be relevant to the project's use cases
- Both description and keywords fields must be present
- Do NOT wrap JSON in markdown code blocks
`;
const descriptionTaskPrompt = `
You create a project description and keywords for an npm package.
PROJECT DIRECTORY: ${this.projectDir}
Use the filesystem tool to explore the project and understand what it does:
1. First, use tree to see the project structure
Use the filesystem tools to explore the project and understand what it does:
1. First, use list_directory to see the project structure
2. Read package.json to understand the package name and current description
3. Read npmextra.json if it exists for additional metadata
4. Read key source files in ts/ directory to understand the implementation
@@ -83,16 +59,20 @@ Your answer should be parseable with JSON.parse() without modifying anything.
Don't wrap the JSON in \`\`\`json\`\`\` - just return the raw JSON object.
`;
const descriptionResult = await descriptionOrchestrator.run(descriptionTaskPrompt);
await descriptionOrchestrator.stop();
logger.log('info', 'Starting description generation with agent...');
if (!descriptionResult.success) {
throw new Error(`Description generation failed: ${descriptionResult.status}`);
}
const descriptionResult = await plugins.smartagent.runAgent({
model: this.aiDocsRef.model,
prompt: descriptionTaskPrompt,
system: descriptionSystemPrompt,
tools: fsTools,
maxSteps: 15,
onToolCall: (toolName) => logger.log('info', `[Description] Tool call: ${toolName}`),
});
console.log(descriptionResult.result);
console.log(descriptionResult.text);
const resultObject: IDescriptionInterface = JSON.parse(
descriptionResult.result.replace('```json', '').replace('```', ''),
descriptionResult.text.replace('```json', '').replace('```', ''),
);
// Use ProjectContext to get file handles for writing
@@ -120,6 +100,6 @@ Don't wrap the JSON in \`\`\`json\`\`\` - just return the raw JSON object.
console.log(`\n======================\n`);
console.log(JSON.stringify(resultObject, null, 2));
console.log(`\n======================\n`);
return descriptionResult.result;
return descriptionResult.text;
}
}

View File

@@ -28,55 +28,31 @@ export class Readme {
console.log(error);
}
// Use DualAgentOrchestrator with filesystem tool for agent-driven exploration
const readmeOrchestrator = new plugins.smartagent.DualAgentOrchestrator({
smartAiInstance: this.aiDocsRef.smartAiInstance,
defaultProvider: 'openai',
maxIterations: 25,
maxResultChars: 15000, // Limit tool output to prevent token explosion
maxHistoryMessages: 20, // Limit history window
logPrefix: '[README]',
onProgress: (event) => logger.log(event.logLevel, event.logMessage),
guardianPolicyPrompt: `
You validate README generation tool calls and outputs.
// Use runAgent with filesystem tool for agent-driven exploration
const fsTools = plugins.smartagentTools.filesystemTool({ rootDir: this.projectDir });
APPROVE tool calls for:
- Reading any files within the project directory (package.json, ts/*.ts, readme.md, etc.)
- Using tree to see project structure
- Using glob to find source files
- Listing directory contents
REJECT tool calls for:
- Reading files outside the project directory
- Writing, deleting, or modifying any files
- Any destructive operations
For final README output, APPROVE if:
- README follows proper markdown format
- Contains Install and Usage sections
- Code examples are correct TypeScript/ESM syntax
- Documentation is comprehensive and helpful
REJECT final output if:
- README is incomplete or poorly formatted
- Contains licensing information (added separately)
- Uses CommonJS syntax instead of ESM
- Contains "in conclusion" or similar filler
`,
});
// Register scoped filesystem tool for agent exploration
readmeOrchestrator.registerScopedFilesystemTool(this.projectDir);
await readmeOrchestrator.start();
const readmeTaskPrompt = `
const readmeSystemPrompt = `
You create markdown READMEs for npm projects. You only output the markdown readme.
You have access to filesystem tools to explore the project. Use them to understand the codebase.
IMPORTANT RULES:
- Only READ files within the project directory
- Do NOT write, delete, or modify any files
- README must follow proper markdown format
- Must contain Install and Usage sections
- Code examples must use correct TypeScript/ESM syntax
- Documentation must be comprehensive and helpful
- Do NOT include licensing information (added separately)
- Do NOT use CommonJS syntax - only ESM
- Do NOT include "in conclusion" or similar filler
`;
const readmeTaskPrompt = `
PROJECT DIRECTORY: ${this.projectDir}
Use the filesystem tool to explore the project and understand what it does:
1. First, use tree to see the project structure (maxDepth: 3)
Use the filesystem tools to explore the project and understand what it does:
1. First, use list_directory to see the project structure
2. Read package.json to understand the package name, description, and dependencies
3. Read the existing readme.md if it exists (use it as a base, improve and expand)
4. Read readme.hints.md if it exists (contains hints for documentation)
@@ -106,15 +82,19 @@ Then generate a comprehensive README following this template:
]
`;
const readmeResult = await readmeOrchestrator.run(readmeTaskPrompt);
await readmeOrchestrator.stop();
logger.log('info', 'Starting README generation with agent...');
if (!readmeResult.success) {
throw new Error(`README generation failed: ${readmeResult.status}`);
}
const readmeResult = await plugins.smartagent.runAgent({
model: this.aiDocsRef.model,
prompt: readmeTaskPrompt,
system: readmeSystemPrompt,
tools: fsTools,
maxSteps: 25,
onToolCall: (toolName) => logger.log('info', `[README] Tool call: ${toolName}`),
});
// Clean up markdown formatting if wrapped in code blocks
let resultMessage = readmeResult.result
let resultMessage = readmeResult.text
.replace(/^```markdown\n?/i, '')
.replace(/\n?```$/i, '');
@@ -142,40 +122,19 @@ Then generate a comprehensive README following this template:
.encoding('utf8')
.read();
// Create a new orchestrator with filesystem tool for each submodule
const subModuleOrchestrator = new plugins.smartagent.DualAgentOrchestrator({
smartAiInstance: this.aiDocsRef.smartAiInstance,
defaultProvider: 'openai',
maxIterations: 20,
maxResultChars: 12000,
maxHistoryMessages: 15,
logPrefix: `[README:${subModule}]`,
onProgress: (event) => logger.log(event.logLevel, event.logMessage),
guardianPolicyPrompt: `
You validate README generation for submodules.
const subModuleFsTools = plugins.smartagentTools.filesystemTool({ rootDir: subModulePath });
APPROVE tool calls for:
- Reading any files within the submodule directory
- Using tree to see structure
- Using glob to find source files
const subModuleSystemPrompt = `
You create markdown READMEs for npm projects. You only output the markdown readme.
REJECT tool calls for:
- Reading files outside the submodule directory
- Writing, deleting, or modifying any files
- Any destructive operations
APPROVE final README if comprehensive, well-formatted markdown with ESM TypeScript examples.
REJECT incomplete READMEs or those with licensing info.
`,
});
// Register scoped filesystem tool for the submodule directory
subModuleOrchestrator.registerScopedFilesystemTool(subModulePath);
await subModuleOrchestrator.start();
IMPORTANT RULES:
- Only READ files within the submodule directory
- Do NOT write, delete, or modify any files
- README must be comprehensive, well-formatted markdown with ESM TypeScript examples
- Do NOT include licensing information (added separately)
`;
const subModulePrompt = `
You create markdown READMEs for npm projects. You only output the markdown readme.
SUB MODULE: ${subModule}
SUB MODULE DIRECTORY: ${subModulePath}
@@ -183,8 +142,8 @@ IMPORTANT: YOU ARE CREATING THE README FOR THIS SUB MODULE: ${subModule}
The Sub Module will be published with:
${JSON.stringify(tspublishData, null, 2)}
Use the filesystem tool to explore the submodule:
1. Use tree to see the submodule structure
Use the filesystem tools to explore the submodule:
1. Use list_directory to see the submodule structure
2. Read package.json to understand the submodule
3. Read source files in ts/ directory to understand the implementation
@@ -208,21 +167,23 @@ Generate a README following the template:
Don't use \`\`\` at the beginning or end. Only for code blocks.
`;
const subModuleResult = await subModuleOrchestrator.run(subModulePrompt);
await subModuleOrchestrator.stop();
const subModuleResult = await plugins.smartagent.runAgent({
model: this.aiDocsRef.model,
prompt: subModulePrompt,
system: subModuleSystemPrompt,
tools: subModuleFsTools,
maxSteps: 20,
onToolCall: (toolName) => logger.log('info', `[README:${subModule}] Tool call: ${toolName}`),
});
if (subModuleResult.success) {
const subModuleReadmeString = subModuleResult.result
.replace(/^```markdown\n?/i, '')
.replace(/\n?```$/i, '') + '\n' + legalInfo;
await plugins.fsInstance
.file(plugins.path.join(subModulePath, 'readme.md'))
.encoding('utf8')
.write(subModuleReadmeString);
logger.log('success', `Built readme for ${subModule}`);
} else {
logger.log('error', `Failed to build readme for ${subModule}: ${subModuleResult.status}`);
}
const subModuleReadmeString = subModuleResult.text
.replace(/^```markdown\n?/i, '')
.replace(/\n?```$/i, '') + '\n' + legalInfo;
await plugins.fsInstance
.file(plugins.path.join(subModulePath, 'readme.md'))
.encoding('utf8')
.write(subModuleReadmeString);
logger.log('success', `Built readme for ${subModule}`);
}
return resultMessage;

View File

@@ -8,7 +8,7 @@ export class AiDoc {
public npmextraKV: plugins.npmextra.KeyValueStore;
public qenvInstance: plugins.qenv.Qenv;
public aidocInteract: plugins.smartinteract.SmartInteract;
public smartAiInstance: plugins.smartai.SmartAi;
public model: plugins.smartai.LanguageModelV3;
argvArg: any;
@@ -84,27 +84,16 @@ export class AiDoc {
this.openaiToken = await this.npmextraKV.readKey('OPENAI_TOKEN');
}
// lets assume we have an OPENAI_Token now
this.smartAiInstance = new plugins.smartai.SmartAi({
openaiToken: this.openaiToken,
// Create model using getModel()
this.model = plugins.smartai.getModel({
provider: 'openai',
model: 'gpt-5.4',
apiKey: this.openaiToken,
});
await this.smartAiInstance.start();
}
public async stop() {
if (this.smartAiInstance) {
await this.smartAiInstance.stop();
}
// No explicit cleanup needed for npmextraKV or aidocInteract
// They don't keep event loop alive
}
/**
* Get the OpenAI provider for direct chat calls
* This is a convenience getter to access the provider from SmartAi
*/
public get openaiProvider(): plugins.smartai.OpenAiProvider {
return this.smartAiInstance.openaiProvider;
// No lifecycle management needed with getModel() API
}
public getOpenaiToken(): string {
@@ -130,7 +119,7 @@ export class AiDoc {
const projectContextInstance = new aiDocsClasses.ProjectContext(projectDirArg);
return await projectContextInstance.gatherFiles();
}
/**
* Get the context with token count information
* @param projectDirArg The path to the project directory
@@ -141,7 +130,7 @@ export class AiDoc {
await projectContextInstance.update();
return projectContextInstance.getContextWithTokenCount();
}
/**
* Get just the token count for a project's context
* @param projectDirArg The path to the project directory
@@ -152,7 +141,7 @@ export class AiDoc {
await projectContextInstance.update();
return projectContextInstance.getTokenCount();
}
/**
* Estimate token count in a text string
* @param text The text to estimate tokens for

View File

@@ -7,6 +7,7 @@ export { path };
import * as npmextra from '@push.rocks/npmextra';
import * as qenv from '@push.rocks/qenv';
import * as smartagent from '@push.rocks/smartagent';
import * as smartagentTools from '@push.rocks/smartagent/tools';
import * as smartai from '@push.rocks/smartai';
import * as smartcli from '@push.rocks/smartcli';
import * as smartdelay from '@push.rocks/smartdelay';
@@ -24,6 +25,7 @@ export {
npmextra,
qenv,
smartagent,
smartagentTools,
smartai,
smartcli,
smartdelay,