Skip to content

Commit 4fe4aee

Browse files
committed
add: public-ready features including auto-initialization, MIT license, and updated documentation with PAI credits
1 parent 55d2a91 commit 4fe4aee

8 files changed

Lines changed: 142 additions & 163 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ dist
88
.opencode/scratchpad
99
bun.lockb
1010
.jules
11+
.claude/

.jules/sentinel.md

Lines changed: 0 additions & 6 deletions
This file was deleted.

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 fprime
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
A native OpenCode plugin that implements the **Personal AI Infrastructure (PAI)** logic, replacing legacy hook scripts with a cohesive, lifecycle-aware system.
44

5+
## Credits & Inspiration
6+
7+
This project is an OpenCode-compatible clone of the hook system from **Dan Miessler's** [Personal AI Infrastructure (PAI)](https://github.com/danielmiessler/Personal_AI_Infrastructure) project. A massive shout out to Dan for the architectural vision and the original PAI patterns that this plugin brings to the OpenCode ecosystem.
8+
59
## Features
610

711
### 1. Identity & Context Injection
@@ -33,44 +37,35 @@ The plugin centers around the `PAI_DIR` environment variable.
3337
| `ENGINEER_NAME` | Your name/identity | `Engineer` |
3438
| `DA_COLOR` | UI color theme for your DA | `blue` |
3539

36-
## Installation
37-
38-
The easiest way to install the plugin and initialize your PAI infrastructure is using the setup script:
40+
## Quick Start
3941

40-
```bash
41-
curl -sSL https://raw.githubusercontent.com/fpr1m3/opencode-pai-plugin/main/setup.sh | bash
42-
```
43-
44-
Or, if you have already cloned the repository:
42+
Add the plugin to your global `opencode.json` configuration file (typically located at `~/.config/opencode/opencode.json`). OpenCode will automatically install the plugin from GitHub on its next startup.
4543

46-
```bash
47-
./setup.sh
44+
```json
45+
{
46+
"plugins": [
47+
"github:fpr1m3/opencode-pai-plugin"
48+
]
49+
}
4850
```
4951

50-
## Manual Installation
51-
52-
```bash
53-
bun add github:fpr1m3/opencode-pai-plugin
54-
```
52+
Upon first run, the plugin will automatically:
53+
1. Detect or create your `PAI_DIR` (default: `$XDG_CONFIG_HOME/opencode`).
54+
2. Initialize the required directory structure for skills and history.
55+
3. Create a default `SKILL.md` core identity if one does not exist.
5556

5657
## Development & Testing
5758

58-
We provide scripts to verify the installation flow in a pristine environment:
59+
We provide scripts to verify the plugin in a pristine environment:
5960

6061
* `./scripts/create-test-env.sh`: Creates a fresh, isolated OpenCode project for testing.
61-
* `./scripts/test-full-flow.sh`: Runs a complete E2E installation and verification.
62-
63-
64-
## Usage
62+
* `./scripts/test-full-flow.sh`: Runs a complete E2E verification of the plugin lifecycle.
6563

66-
Register the plugin in your `.opencode/plugins.ts` (or equivalent):
64+
## Roadmap / TODO
6765

68-
```typescript
69-
import { PAIPlugin } from "@opencode-ai/opencode-pai";
70-
71-
export default PAIPlugin;
72-
```
66+
- [ ] **Voice Server Integration**: Implementation of the PAI voice notification server to provide audible feedback on task completion.
67+
- [ ] **Enhanced Agent Mapping**: More granular tracking of subagent state transitions.
7368

7469
---
7570

76-
**Note**: This plugin is designed to work with the PAI ecosystem and requires a valid `PAI_DIR` structure to function fully.
71+
**Note**: This plugin is designed to work with the PAI ecosystem. While it auto-initializes a basic structure, you can customize your identity by editing `$PAI_DIR/skills/core/SKILL.md`.

scripts/test-full-flow.sh

Lines changed: 5 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,19 @@
11
#!/bin/bash
2-
# test-full-flow.sh - End-to-end test for PAI Plugin setup
2+
# test-full-flow.sh - End-to-end test for PAI Plugin Auto-Initialization
33

44
set -e
55

66
REPO_ROOT=$(pwd)
77
TEST_DIR="/tmp/opencode-full-test-$(date +%s)"
88

9-
# --- Cleanup ---
10-
cleanup() {
11-
echo "🧹 Cleaning up test directory..."
12-
rm -rf "$TEST_DIR"
13-
}
14-
# trap cleanup EXIT # Uncomment if you want auto-cleanup
15-
169
# 1. Establish Pristine Environment
1710
./scripts/create-test-env.sh "$TEST_DIR"
1811

19-
# 2. Preparation for Setup
20-
# We override the package to point to the local repo for the test
21-
export PLUGIN_PACKAGE_OVERRIDE="$REPO_ROOT"
12+
# 2. Preparation
2213
export PAI_DIR="$TEST_DIR/local-pai"
2314

24-
cd "$TEST_DIR"
25-
26-
echo "🛠️ Running setup script inside test environment..."
27-
export PAI_NON_INTERACTIVE="true"
28-
"$REPO_ROOT/setup.sh"
29-
30-
# 3. Verification
31-
echo "🔍 Verifying installation artifacts..."
32-
33-
if [ ! -f ".opencode/plugins/pai.ts" ]; then
34-
echo "❌ Error: Plugin registration file (.opencode/plugins/pai.ts) not found."
35-
exit 1
36-
fi
37-
38-
if [ ! -f "local-pai/skills/core/SKILL.md" ]; then
39-
echo "❌ Error: PAI identity file (local-pai/skills/core/SKILL.md) not found."
40-
exit 1
41-
fi
42-
43-
if ! grep -q "Personal AI Infrastructure" local-pai/skills/core/SKILL.md; then
44-
echo "❌ Error: SKILL.md content is invalid or empty."
45-
exit 1
46-
fi
47-
48-
# Check if dependencies were added to package.json
49-
if ! grep -q "opencode-pai-plugin" package.json; then
50-
echo "❌ Error: Plugin not found in package.json dependencies."
51-
exit 1
52-
fi
15+
echo "🛠️ Verifying auto-initialization via plugin lifecycle..."
16+
cd "$REPO_ROOT"
17+
bun scripts/verify-auto-init.ts
5318

5419
echo "✅ End-to-end verification successful!"
55-
echo "📍 Test project remains at: $TEST_DIR"

scripts/verify-auto-init.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { join } from "path";
2+
import { existsSync, rmSync, mkdirSync } from "fs";
3+
4+
async function testAutoInit() {
5+
console.log("🧪 Testing PAI Plugin Auto-Initialization...");
6+
7+
const worktree = "/tmp/pai-auto-init-test";
8+
if (existsSync(worktree)) rmSync(worktree, { recursive: true });
9+
mkdirSync(worktree, { recursive: true });
10+
11+
// Point PAI_DIR to a temporary location
12+
const testPaiDir = join(worktree, "pai-home");
13+
process.env.PAI_DIR = testPaiDir;
14+
15+
console.log(`📍 Test PAI_DIR: ${testPaiDir}`);
16+
17+
// 1. Initialize Plugin (Dynamic import to pick up env changes)
18+
const { PAIPlugin } = await import("../src/index");
19+
await PAIPlugin({ worktree } as any);
20+
21+
// 2. Verify Directories
22+
const expectedDirs = [
23+
join(testPaiDir, 'skills', 'core'),
24+
join(testPaiDir, 'history', 'raw-outputs'),
25+
join(testPaiDir, 'history', 'sessions'),
26+
];
27+
28+
for (const dir of expectedDirs) {
29+
if (existsSync(dir)) {
30+
console.log(`✅ Directory exists: ${dir}`);
31+
} else {
32+
console.error(`❌ Directory missing: ${dir}`);
33+
process.exit(1);
34+
}
35+
}
36+
37+
// 3. Verify SKILL.md
38+
const skillPath = join(testPaiDir, 'skills', 'core', 'SKILL.md');
39+
if (existsSync(skillPath)) {
40+
console.log(`✅ SKILL.md created at ${skillPath}`);
41+
} else {
42+
console.error(`❌ SKILL.md missing!`);
43+
process.exit(1);
44+
}
45+
46+
console.log("✨ Auto-Initialization verification successful!");
47+
}
48+
49+
testAutoInit().catch(err => {
50+
console.error(err);
51+
process.exit(1);
52+
});

setup.sh

Lines changed: 0 additions & 88 deletions
This file was deleted.

src/index.ts

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,44 @@ import { Logger } from './lib/logger';
44
import { PAI_DIR } from './lib/paths';
55
import { validateCommand } from './lib/security';
66
import { join } from 'path';
7-
import { existsSync, readFileSync } from 'fs';
7+
import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'fs';
8+
9+
/**
10+
* Ensure the PAI directory structure exists.
11+
*/
12+
function ensurePAIStructure() {
13+
const dirs = [
14+
join(PAI_DIR, 'skills', 'core'),
15+
join(PAI_DIR, 'history', 'raw-outputs'),
16+
join(PAI_DIR, 'history', 'sessions'),
17+
join(PAI_DIR, 'history', 'system-logs'),
18+
];
19+
20+
for (const dir of dirs) {
21+
if (!existsSync(dir)) {
22+
try {
23+
mkdirSync(dir, { recursive: true });
24+
console.log(`PAI: Created directory ${dir}`);
25+
} catch (e) {
26+
console.error(`PAI: Failed to create directory ${dir}:`, e);
27+
}
28+
}
29+
}
30+
31+
const coreSkillPath = join(PAI_DIR, 'skills', 'core', 'SKILL.md');
32+
if (!existsSync(coreSkillPath)) {
33+
const defaultSkill = `# PAI Core Identity
34+
You are {{DA}}, a Personal AI Infrastructure.
35+
Your primary engineer is {{ENGINEER_NAME}}.
36+
`;
37+
try {
38+
writeFileSync(coreSkillPath, defaultSkill, 'utf-8');
39+
console.log(`PAI: Created default SKILL.md at ${coreSkillPath}`);
40+
} catch (e) {
41+
console.error(`PAI: Failed to create default SKILL.md:`, e);
42+
}
43+
}
44+
}
845

946
/**
1047
* Check if an event should be skipped to prevent recursive logging.
@@ -63,6 +100,9 @@ export const PAIPlugin: Plugin = async ({ worktree }) => {
63100
let logger: Logger | null = null;
64101
let currentSessionId: string | null = null;
65102

103+
// Auto-initialize PAI infrastructure if needed
104+
ensurePAIStructure();
105+
66106
// Load CORE skill content from $PAI_DIR/skills/core/SKILL.md
67107
let coreSkillContent = '';
68108
const coreSkillPath = join(PAI_DIR, 'skills', 'core', 'SKILL.md');

0 commit comments

Comments
 (0)