# AGENTS.md

This file provides guidance to AI coding agents on how to create plugins for the Foliko Framework system.

## Plugin File Location

### User Plugins: `.agent/plugins/` (auto-loaded)

User plugins go in `.agent/plugins/` and are **automatically loaded** on bootstrap.

**Recommended: Use folder structure for complex plugins**

```
项目目录/
└── .agent/
    └── plugins/
        ├── my-plugin/              ✅ folder structure (recommended)
        │   ├── package.json        # optional, main field specifies entry
        │   ├── index.js            # default entry point
        │   └── node_modules/       # optional, plugin-private dependencies
        ├── another-plugin/         ✅ another folder plugin
        │   └── index.js
        └── legacy.js               ✅ single-file still supported
```

**Why folder structure?**

- Supports `package.json` with `main` field for custom entry points
- Supports `node_modules` for plugin-private dependencies
- Better organization for complex plugins

### Built-in Plugins: `plugins/` (internal)

Built-in framework plugins are in `plugins/` directory.

## Plugin Export Formats

### Folder structure (recommended for `.agent/plugins/`)

```
.agent/plugins/my-plugin/
├── package.json      # optional
└── index.js         # entry point
```

```json
// package.json example
{
  "name": "my-plugin",
  "main": "index.js"
}
```

```javascript
// .agent/plugins/my-plugin/index.js
module.exports = function (Plugin) {
  return class MyPlugin extends Plugin {
    constructor(config = {}) {
      super();
      this.name = 'my-plugin';
      this.version = '1.0.0';
      this.description = '我的插件';
      this.priority = 10;
    }

    install(framework) {
      const { z } = require('zod');
      framework.registerTool({
        name: 'my_tool',
        description: '工具描述',
        inputSchema: z.object({
          param: z.string().describe('参数描述'),
        }),
        execute: async (args, framework) => {
          return { success: true, result: args.param };
        },
      });
      return this;
    }

    uninstall(framework) {
      // cleanup
    }
  };
};
```

### Single-file structure (still supported)

```javascript
// .agent/plugins/my-plugin.js
module.exports = function (Plugin) {
  return class MyPlugin extends Plugin {
    // ... same as above
  };
};
```

**Key points:**

- `Plugin` base class passed automatically by system (no require needed)
- Factory function returns plugin class
- Use `require('zod')` inside methods
- Folder takes priority over single-file if both exist with same name

### Traditional format for `plugins/` (built-in)

```javascript
// plugins/my-plugin.js
const { Plugin } = require('../src/core/plugin-base');
const { z } = require('zod');

class MyPlugin extends Plugin {
  constructor(config = {}) {
    super();
    this.name = 'my-plugin';
    this.version = '1.0.0';
    this.description = '我的插件';
    this.priority = 10;
  }

  install(framework) {
    framework.registerTool({
      name: 'my_tool',
      description: '工具描述',
      inputSchema: z.object({
        param: z.string().describe('参数描述'),
      }),
      execute: async (args, framework) => {
        return { success: true, result: args.param };
      },
    });
    return this;
  }

  uninstall(framework) {}
}

module.exports = { MyPlugin };
```

## Plugin Properties

| Property      | Type   | Required | Description               |
| ------------- | ------ | -------- | ------------------------- |
| `name`        | string | ✅       | Unique name               |
| `version`     | string | ❌       | Version, default '1.0.0'  |
| `description` | string | ❌       | Description               |
| `priority`    | number | ❌       | Load priority, default 10 |

## Lifecycle Methods

| Method                 | Called When        | Required    |
| ---------------------- | ------------------ | ----------- |
| `install(framework)`   | Plugin installed   | ✅          |
| `start(framework)`     | Plugin started     | Recommended |
| `reload(framework)`    | Hot reload         | Optional    |
| `uninstall(framework)` | Plugin uninstalled | Recommended |

## Tool Registration

In `install()` method, register tools using `framework.registerTool()`:

```javascript
install(framework) {
  const { z } = require('zod')
  framework.registerTool({
    name: 'my_tool',
    description: '工具描述',
    inputSchema: z.object({
      param: z.string().describe('参数描述')
    }),
    execute: async (args, framework) => {
      return { success: true, result: args.param }
    }
  })
  return this
}
```

## Framework Object

The framework object provides:

| Method                              | Description                     |
| ----------------------------------- | ------------------------------- |
| `framework.registerTool(tool)`      | Register tool                   |
| `framework.getTools()`              | Get all tools                   |
| `framework.executeTool(name, args)` | Execute tool                    |
| `framework.callTool(name, args)`    | Call tool (for installing deps) |
| `framework.createAgent(config)`     | Create Agent                    |
| `framework.reloadPlugin(name)`      | Reload single plugin            |
| `framework.reloadAllPlugins()`      | Reload all plugins              |

## Dependency Management

Use the `install` tool to install npm packages:

| Plugin Type            | Install Location                           | Command                                                           |
| ---------------------- | ------------------------------------------ | ----------------------------------------------------------------- |
| **Folder plugin**      | `.agent/plugins/plugin-name/node_modules/` | `install({ package: "pkg", path: ".agent/plugins/plugin-name" })` |
| **Single-file plugin** | `.agent/node_modules/`                     | `install({ package: "pkg" })`                                     |

```javascript
// Folder plugin - install to plugin directory
await framework.callTool('install', {
  package: 'axios',
  path: '.agent/plugins/my-plugin',
});

// Single-file plugin - install to .agent
await framework.callTool('install', {
  package: 'zod',
});

// Install from package.json
await framework.callTool('install', {
  file: './my-plugin/package.json',
  path: '.agent/plugins/my-plugin',
});
```

**When encountering `Cannot find module 'xxx'` error:**

1. Identify plugin directory
2. Call `install` tool with `path` parameter for folder plugins
3. Reload plugin
4. Report status to user

## Common Mistakes

1. ❌ Forgetting `install()` - tools won't be registered
2. ❌ Forgetting `return this` - chain calls will fail
3. ❌ Using `parameters` instead of `inputSchema`
4. ❌ Registering tools outside `install()`
5. ❌ Using same name for folder and file - folder takes priority, file will be ignored
