@orderful/droid 0.2.0 → 0.4.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.
Files changed (50) hide show
  1. package/.claude/CLAUDE.md +41 -0
  2. package/.github/workflows/changeset-check.yml +43 -0
  3. package/.github/workflows/release.yml +6 -3
  4. package/CHANGELOG.md +43 -0
  5. package/bun.lock +357 -14
  6. package/dist/agents/README.md +137 -0
  7. package/dist/bin/droid.js +12 -1
  8. package/dist/bin/droid.js.map +1 -1
  9. package/dist/commands/setup.d.ts +8 -0
  10. package/dist/commands/setup.d.ts.map +1 -1
  11. package/dist/commands/setup.js +67 -0
  12. package/dist/commands/setup.js.map +1 -1
  13. package/dist/commands/tui.d.ts +2 -0
  14. package/dist/commands/tui.d.ts.map +1 -0
  15. package/dist/commands/tui.js +737 -0
  16. package/dist/commands/tui.js.map +1 -0
  17. package/dist/lib/agents.d.ts +53 -0
  18. package/dist/lib/agents.d.ts.map +1 -0
  19. package/dist/lib/agents.js +149 -0
  20. package/dist/lib/agents.js.map +1 -0
  21. package/dist/lib/skills.d.ts +20 -0
  22. package/dist/lib/skills.d.ts.map +1 -1
  23. package/dist/lib/skills.js +102 -0
  24. package/dist/lib/skills.js.map +1 -1
  25. package/dist/lib/types.d.ts +5 -0
  26. package/dist/lib/types.d.ts.map +1 -1
  27. package/dist/lib/version.d.ts +5 -0
  28. package/dist/lib/version.d.ts.map +1 -1
  29. package/dist/lib/version.js +19 -1
  30. package/dist/lib/version.js.map +1 -1
  31. package/dist/skills/README.md +85 -0
  32. package/dist/skills/comments/SKILL.md +8 -0
  33. package/dist/skills/comments/SKILL.yaml +32 -0
  34. package/dist/skills/comments/commands/README.md +58 -0
  35. package/package.json +15 -2
  36. package/src/agents/README.md +137 -0
  37. package/src/bin/droid.ts +12 -1
  38. package/src/commands/setup.ts +77 -0
  39. package/src/commands/tui.tsx +1535 -0
  40. package/src/lib/agents.ts +186 -0
  41. package/src/lib/skills.test.ts +75 -1
  42. package/src/lib/skills.ts +125 -0
  43. package/src/lib/types.ts +7 -0
  44. package/src/lib/version.test.ts +20 -1
  45. package/src/lib/version.ts +19 -1
  46. package/src/skills/README.md +85 -0
  47. package/src/skills/comments/SKILL.md +8 -0
  48. package/src/skills/comments/SKILL.yaml +32 -0
  49. package/src/skills/comments/commands/README.md +58 -0
  50. package/tsconfig.json +5 -3
@@ -0,0 +1,85 @@
1
+ # Contributing Skills
2
+
3
+ Skills are reusable AI capabilities that can be installed into Claude Code or OpenCode.
4
+
5
+ ## Directory Structure
6
+
7
+ Each skill is a directory containing:
8
+
9
+ ```
10
+ skills/
11
+ └── my-skill/
12
+ ├── SKILL.yaml # Required: Manifest with metadata
13
+ ├── SKILL.md # Required: Instructions for the AI
14
+ └── commands/ # Optional: Slash commands
15
+ └── my-command.md
16
+ ```
17
+
18
+ ## SKILL.yaml (Manifest)
19
+
20
+ ```yaml
21
+ name: my-skill # Must match directory name
22
+ description: Short description # Shown in TUI and listings
23
+ version: 1.0.0 # Semver
24
+ status: beta # alpha | beta | stable (optional)
25
+ dependencies: [] # Other skills required (optional)
26
+ provides_output: false # Can this skill be an output target?
27
+
28
+ # Configuration schema (optional)
29
+ config_schema:
30
+ option_name:
31
+ type: string # string | boolean
32
+ description: What this option does
33
+ default: "default value" # Optional default
34
+
35
+ # Examples shown in TUI (optional)
36
+ examples:
37
+ - title: "Example name"
38
+ code: |
39
+ // Example code block
40
+ ```
41
+
42
+ ## SKILL.md (AI Instructions)
43
+
44
+ The SKILL.md file contains instructions for the AI. It must have YAML frontmatter:
45
+
46
+ ```markdown
47
+ ---
48
+ name: my-skill
49
+ description: Short description (must match SKILL.yaml)
50
+ globs:
51
+ - "**/*" # File patterns this skill applies to
52
+ alwaysApply: false # Always include in context?
53
+ ---
54
+
55
+ # My Skill
56
+
57
+ Instructions for the AI on how to use this skill...
58
+ ```
59
+
60
+ ## Commands (Optional)
61
+
62
+ Commands are slash commands the user can invoke. Each is a markdown file:
63
+
64
+ ```
65
+ commands/
66
+ └── do-thing.md
67
+ ```
68
+
69
+ The command file is just markdown instructions. The filename becomes the command name (`/do-thing`).
70
+
71
+ ## Testing Your Skill
72
+
73
+ 1. Run `npm run build` to compile
74
+ 2. Run `droid` to open the TUI
75
+ 3. Navigate to Skills tab
76
+ 4. Install your skill
77
+ 5. Test in Claude Code with `/your-command` or by referencing the skill
78
+
79
+ ## Checklist
80
+
81
+ - [ ] `SKILL.yaml` has all required fields (name, description, version)
82
+ - [ ] `SKILL.md` has valid YAML frontmatter
83
+ - [ ] Name in frontmatter matches directory name
84
+ - [ ] Description matches between SKILL.yaml and SKILL.md
85
+ - [ ] Tests pass: `bun test src/lib/skills.test.ts`
@@ -1,3 +1,11 @@
1
+ ---
2
+ name: comments
3
+ description: Inline conversation in any file via @droid/@user markers
4
+ globs:
5
+ - "**/*"
6
+ alwaysApply: false
7
+ ---
8
+
1
9
  # Comments Skill
2
10
 
3
11
  Enable inline conversation in any file using `> @droid` and `> @{user}` markers.
@@ -16,3 +16,35 @@ config_schema:
16
16
  type: boolean
17
17
  description: Keep original comments after addressing (vs removing them)
18
18
  default: false
19
+ examples:
20
+ - title: "Action request"
21
+ code: |
22
+ // @droid use PascalCase for enum keys
23
+ enum Status {
24
+ PENDING = 'pending'
25
+ }
26
+ - title: "Ask a question"
27
+ code: |
28
+ > @droid Should we cache this?
29
+
30
+ > @fry Yes, add Redis caching here...
31
+ - title: "TODO with context"
32
+ code: |
33
+ // @droid TODO: refactor to async/await
34
+ // The callback pattern is unwieldy
35
+ function fetchData(callback) {
36
+ api.get('/data', callback);
37
+ }
38
+ - title: "Code review note"
39
+ code: |
40
+ // @droid potential memory leak here
41
+ // Clear interval on unmount?
42
+ useEffect(() => {
43
+ setInterval(poll, 1000);
44
+ }, []);
45
+ - title: "Multi-line discussion"
46
+ code: |
47
+ > @droid Best approach for pagination?
48
+ > We have ~10k records.
49
+
50
+ > @fry Use cursor-based, limit 50.
@@ -0,0 +1,58 @@
1
+ # Contributing Commands
2
+
3
+ Commands are slash commands that users invoke in Claude Code or OpenCode. They're bundled with skills.
4
+
5
+ ## Location
6
+
7
+ Commands live in a `commands/` subdirectory within a skill:
8
+
9
+ ```
10
+ skills/
11
+ └── my-skill/
12
+ ├── SKILL.yaml
13
+ ├── SKILL.md
14
+ └── commands/
15
+ ├── README.md # This file
16
+ ├── check.md # /check command
17
+ └── cleanup.md # /cleanup command
18
+ ```
19
+
20
+ ## Command File Format
21
+
22
+ Each command is a simple markdown file. The filename (without `.md`) becomes the command name.
23
+
24
+ **Example: `commands/check.md`**
25
+
26
+ ```markdown
27
+ Scan the codebase for @droid comments and address each one.
28
+
29
+ ## Behavior
30
+
31
+ 1. Search for `> @droid` markers in files
32
+ 2. For each comment found:
33
+ - If it's an action request → execute and remove
34
+ - If it's a question → respond with `> @{user_mention}`
35
+
36
+ ## Arguments
37
+
38
+ - `{path}` - Optional path to scope the search (default: current directory)
39
+
40
+ ## Examples
41
+
42
+ - `/comments check` - Check all files
43
+ - `/comments check src/` - Check only src directory
44
+ ```
45
+
46
+ ## Naming Convention
47
+
48
+ Commands are namespaced by skill. If your skill is `comments`, your commands become:
49
+
50
+ - `commands/check.md` → `/comments check`
51
+ - `commands/cleanup.md` → `/comments cleanup`
52
+
53
+ ## Best Practices
54
+
55
+ 1. **Be specific** - Describe exactly what the command does
56
+ 2. **Include examples** - Show common usage patterns
57
+ 3. **Document arguments** - List any parameters the command accepts
58
+ 4. **Explain behavior** - Break down the steps the AI should follow
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orderful/droid",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "AI workflow toolkit for sharing skills, commands, and agents across the team",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "main": "dist/index.js",
10
10
  "scripts": {
11
- "build": "tsc && cp -r src/skills dist/",
11
+ "build": "tsc && cp -r src/skills dist/ && cp -r src/agents dist/",
12
12
  "dev": "tsc --watch",
13
13
  "start": "bun dist/bin/droid.js",
14
14
  "test": "bun test src/",
@@ -36,21 +36,34 @@
36
36
  "engines": {
37
37
  "node": ">=18.0.0"
38
38
  },
39
+ "publishConfig": {
40
+ "access": "public",
41
+ "registry": "https://registry.npmjs.org/"
42
+ },
39
43
  "dependencies": {
44
+ "@opentui/core": "^0.1.59",
45
+ "@opentui/react": "^0.1.59",
40
46
  "chalk": "^5.3.0",
41
47
  "commander": "^12.1.0",
48
+ "ink": "^6.5.1",
49
+ "ink-select-input": "^6.2.0",
50
+ "ink-text-input": "^6.0.0",
42
51
  "inquirer": "^9.2.15",
43
52
  "ora": "^8.0.1",
53
+ "react": "^19.2.1",
44
54
  "yaml": "^2.4.1"
45
55
  },
46
56
  "devDependencies": {
47
57
  "@changesets/changelog-github": "^0.5.2",
48
58
  "@changesets/cli": "^2.29.8",
49
59
  "@types/bun": "latest",
60
+ "@types/ink-text-input": "^2.0.5",
50
61
  "@types/inquirer": "^9.0.7",
51
62
  "@types/node": "^20.11.24",
63
+ "@types/react": "^19.2.7",
52
64
  "@typescript-eslint/eslint-plugin": "^8.49.0",
53
65
  "@typescript-eslint/parser": "^8.49.0",
66
+ "esbuild": "^0.27.1",
54
67
  "eslint": "^8.57.0",
55
68
  "prettier": "^3.2.5",
56
69
  "typescript": "^5.4.2"
@@ -0,0 +1,137 @@
1
+ # Contributing Agents
2
+
3
+ Agents are specialized AI personas with specific expertise or roles. They augment the AI's capabilities for particular tasks.
4
+
5
+ ## Directory Structure
6
+
7
+ Each agent is a directory containing:
8
+
9
+ ```
10
+ agents/
11
+ └── my-agent/
12
+ ├── AGENT.yaml # Required: Manifest with metadata and persona
13
+ └── AGENT.md # Required: Documentation for users
14
+ ```
15
+
16
+ ## AGENT.yaml (Manifest)
17
+
18
+ ```yaml
19
+ name: my-agent # Must match directory name
20
+ description: Short description # Shown in TUI and listings
21
+ version: 1.0.0 # Semver
22
+ status: alpha # alpha | beta | stable (optional)
23
+
24
+ # Agent type (required)
25
+ mode: subagent # primary | subagent | all
26
+
27
+ # Tools this agent can use (optional)
28
+ tools:
29
+ - Read
30
+ - Glob
31
+ - Grep
32
+ - Bash
33
+
34
+ # Suggested triggers - phrases that might invoke this agent
35
+ triggers:
36
+ - "review my code"
37
+ - "check for bugs"
38
+
39
+ # Persona - system prompt additions for this agent (used if AGENT.md is minimal)
40
+ persona: |
41
+ You are a specialized assistant focused on...
42
+
43
+ Your priorities are:
44
+ 1. First priority
45
+ 2. Second priority
46
+
47
+ Always be specific and constructive.
48
+ ```
49
+
50
+ ### Agent Modes
51
+
52
+ - **`primary`** - Main agents you interact with directly. Cycle through them with Tab key.
53
+ - **`subagent`** - Specialized helpers invoked via @mention (e.g., `@code-reviewer check this`) or by primary agents.
54
+ - **`all`** - Agent works as both primary and subagent.
55
+
56
+ ## AGENT.md (Documentation)
57
+
58
+ The AGENT.md file documents the agent for users:
59
+
60
+ ```markdown
61
+ ---
62
+ name: my-agent
63
+ description: Short description (must match AGENT.yaml)
64
+ ---
65
+
66
+ # My Agent
67
+
68
+ Description of what this agent does and when to use it.
69
+
70
+ ## What It Does
71
+
72
+ - Bullet points of capabilities
73
+ - What it focuses on
74
+ - What it ignores
75
+
76
+ ## Usage
77
+
78
+ Examples of how to invoke or use this agent.
79
+
80
+ ## Output Format
81
+
82
+ Description of how the agent formats its responses.
83
+ ```
84
+
85
+ ## Example Agent
86
+
87
+ See `code-reviewer/` for a complete example:
88
+
89
+ - Reviews code for bugs, security issues, style
90
+ - Categorizes issues by severity (critical/warning/suggestion)
91
+ - References specific file and line numbers
92
+
93
+ ## Ideas for Agents
94
+
95
+ - **test-writer** - Generates unit tests for code
96
+ - **doc-writer** - Writes documentation and comments
97
+ - **refactorer** - Suggests and applies refactoring patterns
98
+ - **security-auditor** - Deep security analysis
99
+ - **performance-optimizer** - Identifies performance bottlenecks
100
+
101
+ ## Installation
102
+
103
+ When you install an agent via the TUI, droid:
104
+
105
+ 1. Reads `AGENT.yaml` for metadata (name, description, tools)
106
+ 2. Reads `AGENT.md` for the agent's instructions/persona
107
+ 3. Combines them into a single `.md` file with frontmatter
108
+ 4. Writes to `~/.claude/agents/{name}.md`
109
+
110
+ The installed format matches what Claude Code expects:
111
+
112
+ ```markdown
113
+ ---
114
+ name: my-agent
115
+ description: Short description
116
+ tools: Read, Glob, Grep, Bash
117
+ ---
118
+
119
+ [Content from AGENT.md]
120
+ ```
121
+
122
+ ## Testing Your Agent
123
+
124
+ 1. Run `npm run build` to compile
125
+ 2. Run `droid` to open the TUI
126
+ 3. Navigate to Agents tab
127
+ 4. Verify your agent appears with correct metadata
128
+ 5. Install and verify it appears in `~/.claude/agents/`
129
+
130
+ ## Checklist
131
+
132
+ - [ ] `AGENT.yaml` has all required fields (name, description, version, mode)
133
+ - [ ] `AGENT.md` contains the agent's instructions/persona
134
+ - [ ] Name matches directory name
135
+ - [ ] Description is clear and concise
136
+ - [ ] Mode is appropriate (subagent for specialized tasks, primary for main assistants)
137
+ - [ ] Tools list only includes what the agent needs
package/src/bin/droid.ts CHANGED
@@ -7,6 +7,7 @@ import { skillsCommand } from '../commands/skills.js';
7
7
  import { installCommand } from '../commands/install.js';
8
8
  import { uninstallCommand } from '../commands/uninstall.js';
9
9
  import { updateCommand } from '../commands/update.js';
10
+ import { tuiCommand } from '../commands/tui.js';
10
11
  import { getVersion, checkForUpdates } from '../lib/version.js';
11
12
 
12
13
  const version = getVersion();
@@ -52,7 +53,17 @@ program
52
53
  .argument('[skill]', 'Update a specific skill')
53
54
  .action(updateCommand);
54
55
 
56
+ program
57
+ .command('tui')
58
+ .description('Launch interactive TUI dashboard')
59
+ .action(tuiCommand);
60
+
55
61
  // Check for updates on any command (non-blocking)
56
62
  checkForUpdates().catch(() => {});
57
63
 
58
- program.parse();
64
+ // If no command provided, launch TUI
65
+ if (process.argv.length === 2) {
66
+ tuiCommand();
67
+ } else {
68
+ program.parse();
69
+ }
@@ -1,10 +1,24 @@
1
1
  import inquirer from 'inquirer';
2
2
  import chalk from 'chalk';
3
3
  import { execSync } from 'child_process';
4
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
5
+ import { join } from 'path';
6
+ import { homedir } from 'os';
4
7
  import { loadConfig, saveConfig, configExists } from '../lib/config.js';
5
8
  import { getBundledSkills } from '../lib/skills.js';
6
9
  import { AITool, BuiltInOutput, type DroidConfig, type OutputPreference } from '../lib/types.js';
7
10
 
11
+ /**
12
+ * Permissions droid needs to operate without constant prompts
13
+ */
14
+ const DROID_PERMISSIONS = [
15
+ 'Read(~/.droid/**)',
16
+ 'Write(~/.droid/**)',
17
+ 'Edit(~/.droid/**)',
18
+ 'Glob(~/.droid/**)',
19
+ 'Grep(~/.droid/**)',
20
+ ];
21
+
8
22
  /**
9
23
  * Detect which AI tool is installed
10
24
  */
@@ -37,6 +51,60 @@ function detectGitUsername(): string {
37
51
  }
38
52
  }
39
53
 
54
+ /**
55
+ * Configure AI tool permissions for droid
56
+ */
57
+ export function configureAIToolPermissions(aiTool: AITool): { added: string[]; alreadyPresent: boolean } {
58
+ const added: string[] = [];
59
+
60
+ if (aiTool === AITool.ClaudeCode) {
61
+ const settingsPath = join(homedir(), '.claude', 'settings.json');
62
+
63
+ // Ensure .claude directory exists
64
+ const claudeDir = join(homedir(), '.claude');
65
+ if (!existsSync(claudeDir)) {
66
+ mkdirSync(claudeDir, { recursive: true });
67
+ }
68
+
69
+ // Load or create settings
70
+ let settings: { permissions?: { allow?: string[]; deny?: string[]; ask?: string[] } } = {};
71
+ if (existsSync(settingsPath)) {
72
+ try {
73
+ settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
74
+ } catch {
75
+ // Invalid JSON, start fresh
76
+ settings = {};
77
+ }
78
+ }
79
+
80
+ // Ensure permissions structure exists
81
+ if (!settings.permissions) {
82
+ settings.permissions = {};
83
+ }
84
+ if (!Array.isArray(settings.permissions.allow)) {
85
+ settings.permissions.allow = [];
86
+ }
87
+
88
+ // Add missing permissions
89
+ for (const perm of DROID_PERMISSIONS) {
90
+ if (!settings.permissions.allow.includes(perm)) {
91
+ settings.permissions.allow.push(perm);
92
+ added.push(perm);
93
+ }
94
+ }
95
+
96
+ // Save if we added anything
97
+ if (added.length > 0) {
98
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
99
+ }
100
+
101
+ return { added, alreadyPresent: added.length === 0 };
102
+ }
103
+
104
+ // OpenCode - TODO: implement when we know the settings path
105
+ return { added: [], alreadyPresent: true };
106
+ }
107
+
40
108
  /**
41
109
  * Get available output options (built-in + skills that provide output)
42
110
  */
@@ -145,5 +213,14 @@ export async function setupCommand(): Promise<void> {
145
213
  saveConfig(config);
146
214
 
147
215
  console.log(chalk.green('\n✓ Config saved to ~/.droid/config.yaml'));
216
+
217
+ // Configure AI tool permissions
218
+ const { added, alreadyPresent } = configureAIToolPermissions(answers.ai_tool);
219
+ if (added.length > 0) {
220
+ console.log(chalk.green(`✓ Added droid permissions to ${answers.ai_tool} settings`));
221
+ } else if (alreadyPresent) {
222
+ console.log(chalk.gray(` Droid permissions already configured in ${answers.ai_tool}`));
223
+ }
224
+
148
225
  console.log(chalk.gray('\nRun `droid skills` to browse and install skills.'));
149
226
  }