@forloop-cc/forloop-opencode-plugin-planner 2.2.1
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/CHANGELOG.md +225 -0
- package/CODE_OF_CONDUCT.md +77 -0
- package/CONTRIBUTING.md +176 -0
- package/LICENSE +21 -0
- package/README.md +211 -0
- package/SECURITY.md +69 -0
- package/docs/CONFIGURATION.md +283 -0
- package/docs/DEVELOPER-VS-USER.md +129 -0
- package/docs/IMPROVED-AUTHENTICATION.md +317 -0
- package/docs/INSTALLATION-SCRIPTS.md +304 -0
- package/docs/PLANNER-AGENT-IMPROVEMENTS.md +88 -0
- package/docs/PLUGIN-ARCHITECTURE.md +308 -0
- package/docs/QUICKSTART-NON-DEV.md +94 -0
- package/docs/README-FOR-HUMANS-AND-AI.md +109 -0
- package/docs/README.md +70 -0
- package/docs/SKILLS-GAP-ANALYSIS.md +157 -0
- package/docs/USER-INTERACTION-MODEL.md +106 -0
- package/docs/file-management/2026-04-12-forloop-aivy-documents-sync.md +395 -0
- package/docs/file-management/FILE_UPLOAD_ENHANCEMENT.md +431 -0
- package/docs/file-management/FILE_UPLOAD_FLOW.md +300 -0
- package/docs/images/forloop-opencode-flow.png +0 -0
- package/docs/images/forloop-opencode-header.png +0 -0
- package/docs/superpowers/plans/2026-05-03-sprint-isolated-directory-structure.md +1450 -0
- package/docs/superpowers/plans/2026-05-29-install-system.md +850 -0
- package/docs/superpowers/specs/2026-05-03-sprint-isolated-directory-structure-design.md +149 -0
- package/docs/superpowers/specs/2026-05-19-opencode-message-recording-design.md +468 -0
- package/docs/superpowers/specs/2026-05-29-install-system-design.md +135 -0
- package/install.sh +317 -0
- package/package.json +87 -0
- package/plugins/capabilities/api-client.ts +556 -0
- package/plugins/capabilities/auth.ts +120 -0
- package/plugins/capabilities/config.ts +195 -0
- package/plugins/capabilities/context-resolver.ts +106 -0
- package/plugins/capabilities/token-storage.ts +98 -0
- package/plugins/forloop-plugin.ts +186 -0
- package/plugins/hooks/message-recorder.ts +258 -0
- package/plugins/hooks/shell-env.ts +62 -0
- package/plugins/tools/agent-sprint-tools.ts +100 -0
- package/plugins/tools/agent-suggestion-tools.ts +275 -0
- package/plugins/tools/agent-tools.ts +114 -0
- package/plugins/tools/ai-trigger-tools.ts +79 -0
- package/plugins/tools/developer-status-tool.ts +97 -0
- package/plugins/tools/file-tools.ts +240 -0
- package/plugins/tools/folder-tools.ts +75 -0
- package/plugins/tools/organization-tools.ts +213 -0
- package/plugins/tools/schedule-tools.ts +173 -0
- package/plugins/tools/sprint-tools.ts +287 -0
- package/plugins/tools/story-tools.ts +320 -0
- package/plugins/tools/sync-tools.ts +509 -0
- package/plugins/tools/template-tools.ts +170 -0
- package/plugins/tools/user-tools.ts +146 -0
- package/scripts/migrate-tokens.js +90 -0
- package/scripts/use-prod.sh +11 -0
- package/tsconfig.json +17 -0
- package/update.sh +172 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
# Improved Token Authentication System
|
|
2
|
+
|
|
3
|
+
## Problem Statement
|
|
4
|
+
|
|
5
|
+
The ForLoop opencode plugin runs in **two different execution contexts**:
|
|
6
|
+
|
|
7
|
+
1. **Local Workspace** (user's machine)
|
|
8
|
+
- User has `floop_*` API key token
|
|
9
|
+
- Token stored in `~/.config/forloop/tokens.json`
|
|
10
|
+
- Used for direct API calls
|
|
11
|
+
|
|
12
|
+
2. **AWS Lambda** (serverless execution)
|
|
13
|
+
- Client sends JWT Bearer token (from user login)
|
|
14
|
+
- Token passed via EventBridge from `server_lambda`
|
|
15
|
+
- Used for authenticated API calls on behalf of user
|
|
16
|
+
|
|
17
|
+
**Previous Issue**: The `validateToken()` function only accepted `floop_*` tokens, which would reject JWT tokens in Lambda execution.
|
|
18
|
+
|
|
19
|
+
## Solution: Dual Token Support
|
|
20
|
+
|
|
21
|
+
### Token Types
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
export type TokenType = 'api_key' | 'jwt';
|
|
25
|
+
|
|
26
|
+
// API Key: floop_abc123xyz
|
|
27
|
+
// JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM...
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Detection Logic (`auth.ts:detectTokenType`)
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
export function detectTokenType(token: string): TokenType | null {
|
|
34
|
+
if (!token) return null;
|
|
35
|
+
|
|
36
|
+
// API Key format: floop_xxx
|
|
37
|
+
if (token.startsWith('floop_')) {
|
|
38
|
+
return 'api_key';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// JWT format: xxx.yyy.zzz (base64url.base64url.base64url)
|
|
42
|
+
const parts = token.split('.');
|
|
43
|
+
if (parts.length === 3 && parts.every(p => p.length > 0)) {
|
|
44
|
+
const base64urlRegex = /^[A-Za-z0-9_-]+$/;
|
|
45
|
+
if (parts.every(p => base64urlRegex.test(p))) {
|
|
46
|
+
return 'jwt';
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Context-Aware Validation
|
|
55
|
+
|
|
56
|
+
**Local Execution:**
|
|
57
|
+
- ✅ Accepts: `floop_*` API keys
|
|
58
|
+
- ❌ Rejects: JWT tokens (with helpful error message)
|
|
59
|
+
|
|
60
|
+
**Lambda Execution:**
|
|
61
|
+
- ✅ Accepts: JWT tokens (from EventBridge)
|
|
62
|
+
- ✅ Accepts: `floop_*` API keys (backward compatible)
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
export async function validateToken(providedToken?: string): Promise<TokenValidationResult> {
|
|
66
|
+
const token = providedToken || (await getToken());
|
|
67
|
+
|
|
68
|
+
const tokenType = detectTokenType(token);
|
|
69
|
+
|
|
70
|
+
if (!tokenType) {
|
|
71
|
+
return { valid: false, error: 'Unrecognized token format...' };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// JWT only allowed in Lambda
|
|
75
|
+
if (tokenType === 'jwt' && !isLambdaExecution()) {
|
|
76
|
+
return {
|
|
77
|
+
valid: false,
|
|
78
|
+
error: 'JWT tokens are only supported in Lambda execution...',
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return { valid: true, token, tokenType };
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Lambda Detection (`config.ts`)
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
export const isLambdaExecution = (): boolean => {
|
|
90
|
+
return !!(
|
|
91
|
+
process.env.AWS_LAMBDA_FUNCTION_NAME ||
|
|
92
|
+
process.env.AWS_EXECUTION_ENV ||
|
|
93
|
+
process.env.LAMBDA_TASK_ROOT
|
|
94
|
+
);
|
|
95
|
+
};
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## HTTP Header Strategy
|
|
99
|
+
|
|
100
|
+
Different token types require different HTTP headers:
|
|
101
|
+
|
|
102
|
+
| Token Type | Header | Example |
|
|
103
|
+
|------------|--------|---------|
|
|
104
|
+
| JWT | `Authorization: Bearer` | `Bearer eyJhbGciOiJIUzI1NiIs...` |
|
|
105
|
+
| API Key | `X-API-Token` | `floop_abc123xyz` |
|
|
106
|
+
|
|
107
|
+
### Dynamic Header Selection (`api-client.ts`)
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
export class ForLoopAPIClient {
|
|
111
|
+
private tokenType: TokenType | null;
|
|
112
|
+
|
|
113
|
+
constructor(config: ClientConfig) {
|
|
114
|
+
this.tokenType = detectTokenType(config.token);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private getAuthHeaders(): HeadersInit {
|
|
118
|
+
const headers: HeadersInit = {};
|
|
119
|
+
|
|
120
|
+
if (this.tokenType === 'jwt') {
|
|
121
|
+
headers['Authorization'] = `Bearer ${this.config.token}`;
|
|
122
|
+
} else {
|
|
123
|
+
headers['X-API-Token'] = this.config.token;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return headers;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
public async request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
|
|
130
|
+
const response = await fetch(url, {
|
|
131
|
+
...options,
|
|
132
|
+
headers: {
|
|
133
|
+
...this.defaultHeaders,
|
|
134
|
+
...this.getAuthHeaders(), // ← Dynamic based on token type
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
return response.json();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Execution Flow
|
|
143
|
+
|
|
144
|
+
### Local Workspace
|
|
145
|
+
```
|
|
146
|
+
┌─────────────────────────────────────┐
|
|
147
|
+
│ User runs opencode locally │
|
|
148
|
+
│ $ opencode run --agent forloop... │
|
|
149
|
+
└─────────────────────────────────────┘
|
|
150
|
+
│
|
|
151
|
+
▼
|
|
152
|
+
┌─────────────────────────────────────┐
|
|
153
|
+
│ Plugin loads ~/.config/forloop/ │
|
|
154
|
+
│ tokens.json → gets floop_* token │
|
|
155
|
+
└─────────────────────────────────────┘
|
|
156
|
+
│
|
|
157
|
+
▼
|
|
158
|
+
┌─────────────────────────────────────┐
|
|
159
|
+
│ validateToken() checks: │
|
|
160
|
+
│ - isLambdaExecution() = false │
|
|
161
|
+
│ - tokenType = 'api_key' ✓ │
|
|
162
|
+
│ - Returns valid ✓ │
|
|
163
|
+
└─────────────────────────────────────┘
|
|
164
|
+
│
|
|
165
|
+
▼
|
|
166
|
+
┌─────────────────────────────────────┐
|
|
167
|
+
│ API calls use header: │
|
|
168
|
+
│ X-API-Token: floop_*** │
|
|
169
|
+
└─────────────────────────────────────┘
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### AWS Lambda
|
|
173
|
+
```
|
|
174
|
+
┌─────────────────────────────────────┐
|
|
175
|
+
│ Client sends POST /api/ai/chat │
|
|
176
|
+
│ Authorization: Bearer eyJ... │
|
|
177
|
+
└─────────────────────────────────────┘
|
|
178
|
+
│
|
|
179
|
+
▼
|
|
180
|
+
┌─────────────────────────────────────┐
|
|
181
|
+
│ server_lambda extracts JWT, │
|
|
182
|
+
│ includes in EventBridge detail │
|
|
183
|
+
└─────────────────────────────────────┘
|
|
184
|
+
│
|
|
185
|
+
▼
|
|
186
|
+
┌─────────────────────────────────────┐
|
|
187
|
+
│ Lambda receives JWT, seeds to │
|
|
188
|
+
│ /tmp/forloop-sandbox/.../tokens.json
|
|
189
|
+
└─────────────────────────────────────┘
|
|
190
|
+
│
|
|
191
|
+
▼
|
|
192
|
+
┌─────────────────────────────────────┐
|
|
193
|
+
│ Plugin reads JWT token │
|
|
194
|
+
└─────────────────────────────────────┘
|
|
195
|
+
│
|
|
196
|
+
▼
|
|
197
|
+
┌─────────────────────────────────────┐
|
|
198
|
+
│ validateToken() checks: │
|
|
199
|
+
│ - isLambdaExecution() = true │
|
|
200
|
+
│ - tokenType = 'jwt' ✓ │
|
|
201
|
+
│ - JWT allowed in Lambda ✓ │
|
|
202
|
+
│ - Returns valid ✓ │
|
|
203
|
+
└─────────────────────────────────────┘
|
|
204
|
+
│
|
|
205
|
+
▼
|
|
206
|
+
┌─────────────────────────────────────┐
|
|
207
|
+
│ API calls use header: │
|
|
208
|
+
│ Authorization: Bearer eyJ... │
|
|
209
|
+
└─────────────────────────────────────┘
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Error Messages
|
|
213
|
+
|
|
214
|
+
### Missing Token
|
|
215
|
+
```
|
|
216
|
+
No API token configured. Please create a token at https://forloop.cc/profile?tab=api-tokens
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Unrecognized Format
|
|
220
|
+
```
|
|
221
|
+
Unrecognized token format. Use either a ForLoop API key (floop_*) or a valid JWT token.
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### JWT in Local Context
|
|
225
|
+
```
|
|
226
|
+
JWT tokens are only supported in Lambda execution. Please use a ForLoop API key (floop_*) for local execution.
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Backward Compatibility
|
|
230
|
+
|
|
231
|
+
✅ **Existing functionality preserved:**
|
|
232
|
+
- `floop_*` tokens work in both local and Lambda
|
|
233
|
+
- `X-API-Token` header still used for API keys
|
|
234
|
+
- Token file location unchanged (`~/.config/forloop/tokens.json`)
|
|
235
|
+
- Profile support maintained
|
|
236
|
+
|
|
237
|
+
✅ **New features:**
|
|
238
|
+
- JWT tokens now accepted in Lambda
|
|
239
|
+
- Automatic header selection based on token type
|
|
240
|
+
- Clear error messages for wrong token type in wrong context
|
|
241
|
+
|
|
242
|
+
## Testing
|
|
243
|
+
|
|
244
|
+
### Local Testing with API Key
|
|
245
|
+
```bash
|
|
246
|
+
# Set API key
|
|
247
|
+
export FORLOOP_API_URL=https://api.forloop.cc
|
|
248
|
+
echo '{"default":"floop_test123"}' > ~/.config/forloop/tokens.json
|
|
249
|
+
|
|
250
|
+
# Run opencode locally
|
|
251
|
+
opencode run --agent forLoopPlanner -- "Create a story..."
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Lambda Testing with JWT
|
|
255
|
+
```bash
|
|
256
|
+
# Lambda automatically detects execution context
|
|
257
|
+
# No manual configuration needed
|
|
258
|
+
# JWT passed from client → server_lambda → EventBridge → Lambda
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Type Detection Unit Test
|
|
262
|
+
```typescript
|
|
263
|
+
import { detectTokenType } from './auth';
|
|
264
|
+
|
|
265
|
+
describe('detectTokenType', () => {
|
|
266
|
+
it('detects API key', () => {
|
|
267
|
+
expect(detectTokenType('floop_abc123')).toBe('api_key');
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('detects JWT', () => {
|
|
271
|
+
const jwt = 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U';
|
|
272
|
+
expect(detectTokenType(jwt)).toBe('jwt');
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it('rejects invalid format', () => {
|
|
276
|
+
expect(detectTokenType('invalid')).toBe(null);
|
|
277
|
+
expect(detectTokenType('')).toBe(null);
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Security Considerations
|
|
283
|
+
|
|
284
|
+
### JWT Validation
|
|
285
|
+
- ✅ Format checked (3 parts, base64url encoding)
|
|
286
|
+
- ✅ Context checked (only in Lambda)
|
|
287
|
+
- ⚠️ Signature not validated (done by API server)
|
|
288
|
+
- ⚠️ Expiration not checked (done by API server)
|
|
289
|
+
|
|
290
|
+
### API Key Validation
|
|
291
|
+
- ✅ Prefix checked (`floop_`)
|
|
292
|
+
- ✅ File permissions (`0o600`)
|
|
293
|
+
- ✅ Isolated in Lambda sandbox
|
|
294
|
+
|
|
295
|
+
### Token Storage
|
|
296
|
+
- Lambda: Ephemeral `/tmp/` storage (cleared after execution)
|
|
297
|
+
- Local: Persistent `~/.config/forloop/` (user-managed)
|
|
298
|
+
|
|
299
|
+
## Migration
|
|
300
|
+
|
|
301
|
+
**No migration required** - changes are fully backward compatible.
|
|
302
|
+
|
|
303
|
+
Existing users with `floop_*` tokens will continue to work without any changes.
|
|
304
|
+
|
|
305
|
+
## Related Files
|
|
306
|
+
|
|
307
|
+
### Core Authentication
|
|
308
|
+
- `plugins/capabilities/auth.ts` - Token validation and type detection
|
|
309
|
+
- `plugins/capabilities/config.ts` - Lambda detection
|
|
310
|
+
- `plugins/capabilities/api-client.ts` - HTTP client with dynamic headers
|
|
311
|
+
- `plugins/capabilities/token-storage.ts` - Token file management
|
|
312
|
+
|
|
313
|
+
### Lambda
|
|
314
|
+
- `forloop-opencode-lambda-planner/src/lambda-handler.mjs` - JWT seeding (lines 92-108)
|
|
315
|
+
|
|
316
|
+
### Tools
|
|
317
|
+
- All tools in `plugins/tools/*.ts` use `validateToken()` for authentication
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# Installation Scripts Reference
|
|
2
|
+
|
|
3
|
+
This document describes the installation and update scripts for the ForLoop Plugin.
|
|
4
|
+
|
|
5
|
+
## install.sh
|
|
6
|
+
|
|
7
|
+
One-line installation script for the ForLoop Plugin.
|
|
8
|
+
|
|
9
|
+
### Quick Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
curl -fsSL https://raw.githubusercontent.com/forloop-cc/forloop-opencode-plugin/main/install.sh | bash
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Usage
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Interactive install (asks questions)
|
|
19
|
+
curl -fsSL https://raw.githubusercontent.com/forloop-cc/forloop-opencode-plugin/main/install.sh | bash
|
|
20
|
+
|
|
21
|
+
# Global install (all projects)
|
|
22
|
+
bash install.sh --global
|
|
23
|
+
|
|
24
|
+
# Local install (current project only)
|
|
25
|
+
bash install.sh --local
|
|
26
|
+
|
|
27
|
+
# Custom directory
|
|
28
|
+
bash install.sh --dir /path/to/plugins
|
|
29
|
+
|
|
30
|
+
# Force reinstall (overwrite existing)
|
|
31
|
+
bash install.sh --force
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Options
|
|
35
|
+
|
|
36
|
+
| Option | Description |
|
|
37
|
+
|--------|-------------|
|
|
38
|
+
| `-g, --global` | Install to `~/.config/opencode` (all projects) |
|
|
39
|
+
| `-l, --local` | Install to `.opencode` (current project) |
|
|
40
|
+
| `-d, --dir PATH` | Install to custom directory |
|
|
41
|
+
| `-f, --force` | Force installation (overwrite without asking) |
|
|
42
|
+
| `-h, --help` | Show help message |
|
|
43
|
+
|
|
44
|
+
### What It Does
|
|
45
|
+
|
|
46
|
+
1. **Checks prerequisites**
|
|
47
|
+
- git (required)
|
|
48
|
+
- Node.js (required for npm install)
|
|
49
|
+
- opencode CLI (optional, warns if missing)
|
|
50
|
+
|
|
51
|
+
2. **Clones the plugin**
|
|
52
|
+
- Git clone from GitHub
|
|
53
|
+
- Shallow clone (faster)
|
|
54
|
+
|
|
55
|
+
3. **Installs dependencies**
|
|
56
|
+
- Runs `npm install --production`
|
|
57
|
+
- No build step required (TypeScript runs directly)
|
|
58
|
+
|
|
59
|
+
4. **Sets up token** (interactive only)
|
|
60
|
+
- Guides you through token creation
|
|
61
|
+
- Can optionally save token during install
|
|
62
|
+
|
|
63
|
+
5. **Verifies installation**
|
|
64
|
+
- Checks entry point exists
|
|
65
|
+
- Provides next steps
|
|
66
|
+
|
|
67
|
+
### Token Setup
|
|
68
|
+
|
|
69
|
+
During interactive installation, you can set up your API token:
|
|
70
|
+
|
|
71
|
+
1. Script prompts: "Have you created a token? [y/N]"
|
|
72
|
+
2. If yes, prompts for token value
|
|
73
|
+
3. Saves to `~/.config/forloop/tokens.json`
|
|
74
|
+
4. Sets permissions to `600` (secure)
|
|
75
|
+
|
|
76
|
+
**If you skip token setup:**
|
|
77
|
+
```bash
|
|
78
|
+
forloopTokenSet --token floop_YOUR_TOKEN_HERE
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Prerequisites
|
|
82
|
+
|
|
83
|
+
| Requirement | Required? | Why |
|
|
84
|
+
|-------------|-----------|-----|
|
|
85
|
+
| git | ✅ Yes | Clones plugin repository |
|
|
86
|
+
| Node.js 18+ | ✅ Yes | Runs npm install |
|
|
87
|
+
| opencode CLI | ⚠️ Recommended | Using the plugin requires it |
|
|
88
|
+
| ForLoop account | ⚠️ Recommended | Need API token to use features |
|
|
89
|
+
|
|
90
|
+
### Troubleshooting
|
|
91
|
+
|
|
92
|
+
**"git is required but not installed"**
|
|
93
|
+
```bash
|
|
94
|
+
# macOS
|
|
95
|
+
brew install git
|
|
96
|
+
|
|
97
|
+
# Ubuntu/Debian
|
|
98
|
+
apt-get install git
|
|
99
|
+
|
|
100
|
+
# Windows
|
|
101
|
+
# Download from https://git-scm.com/download/win
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**"Node.js not found"**
|
|
105
|
+
```bash
|
|
106
|
+
# Install from https://nodejs.org
|
|
107
|
+
# Or use nvm: https://github.com/nvm-sh/nvm
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**"Existing forloop plugin found"**
|
|
111
|
+
```bash
|
|
112
|
+
# Use --force to overwrite
|
|
113
|
+
bash install.sh --force
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Installation failed verification**
|
|
117
|
+
```bash
|
|
118
|
+
# Check installation directory
|
|
119
|
+
ls -la ~/.config/opencode/plugins/forloop/
|
|
120
|
+
# Or for local:
|
|
121
|
+
ls -la .opencode/plugins/forloop/
|
|
122
|
+
|
|
123
|
+
# Entry point should exist:
|
|
124
|
+
# plugins/forloop/plugins/forloop-plugin.ts
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## update.sh
|
|
130
|
+
|
|
131
|
+
Update an existing ForLoop Plugin installation.
|
|
132
|
+
|
|
133
|
+
### Quick Update
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# Auto-detect installation location
|
|
137
|
+
bash update.sh
|
|
138
|
+
|
|
139
|
+
# Update global installation
|
|
140
|
+
bash update.sh --global
|
|
141
|
+
|
|
142
|
+
# Update local installation
|
|
143
|
+
bash update.sh --local
|
|
144
|
+
|
|
145
|
+
# Update custom directory
|
|
146
|
+
bash update.sh --dir /path/to/plugins
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Usage
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
# Check for updates and update if newer
|
|
153
|
+
bash update.sh
|
|
154
|
+
|
|
155
|
+
# Force update to latest version
|
|
156
|
+
bash update.sh --force
|
|
157
|
+
|
|
158
|
+
# Show changelog after update
|
|
159
|
+
bash update.sh --changelog
|
|
160
|
+
|
|
161
|
+
# Update and show changelog
|
|
162
|
+
bash update.sh --global --changelog
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Options
|
|
166
|
+
|
|
167
|
+
| Option | Description |
|
|
168
|
+
|--------|-------------|
|
|
169
|
+
| `-g, --global` | Update global installation (`~/.config/opencode`) |
|
|
170
|
+
| `-l, --local` | Update local installation (`.opencode`) |
|
|
171
|
+
| `-d, --dir PATH` | Update custom directory |
|
|
172
|
+
| `-f, --force` | Force update even if already up to date |
|
|
173
|
+
| `-c, --changelog` | Show changelog after update |
|
|
174
|
+
| `-h, --help` | Show help message |
|
|
175
|
+
|
|
176
|
+
### What It Does
|
|
177
|
+
|
|
178
|
+
1. **Finds installation**
|
|
179
|
+
- Checks global location
|
|
180
|
+
- Checks local location
|
|
181
|
+
- Or uses specified directory
|
|
182
|
+
|
|
183
|
+
2. **Checks for updates**
|
|
184
|
+
- Fetches latest from git
|
|
185
|
+
- Compares current vs latest version
|
|
186
|
+
- Only updates if newer
|
|
187
|
+
|
|
188
|
+
3. **Updates plugin**
|
|
189
|
+
- Switches to main branch
|
|
190
|
+
- Pulls latest changes or checks out tag
|
|
191
|
+
- Reinstalls dependencies
|
|
192
|
+
|
|
193
|
+
4. **Verifies update**
|
|
194
|
+
- Checks entry point exists
|
|
195
|
+
- Shows changelog (if requested)
|
|
196
|
+
|
|
197
|
+
### Update Behavior
|
|
198
|
+
|
|
199
|
+
**With tags (releases):**
|
|
200
|
+
- Updates to latest tagged version
|
|
201
|
+
- Example: `v2.2.0`
|
|
202
|
+
|
|
203
|
+
**Without tags (development):**
|
|
204
|
+
- Updates to latest commit on main branch
|
|
205
|
+
|
|
206
|
+
**Already up to date:**
|
|
207
|
+
- Script exits with "Already up to date!" message
|
|
208
|
+
|
|
209
|
+
**Force mode:**
|
|
210
|
+
- Reinstalls dependencies
|
|
211
|
+
- Useful if dependencies changed
|
|
212
|
+
|
|
213
|
+
### Troubleshooting
|
|
214
|
+
|
|
215
|
+
**"No ForLoop plugin installation found"**
|
|
216
|
+
```bash
|
|
217
|
+
# Specify directory explicitly
|
|
218
|
+
bash update.sh --dir ~/.config/opencode/plugins/forloop
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**"Not a git repository"**
|
|
222
|
+
```bash
|
|
223
|
+
# Directory is not a git clone
|
|
224
|
+
# Reinstall instead:
|
|
225
|
+
bash install.sh --force
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**Update fails**
|
|
229
|
+
```bash
|
|
230
|
+
# Reset to clean state
|
|
231
|
+
cd ~/.config/opencode/plugins/forloop
|
|
232
|
+
git reset --hard HEAD
|
|
233
|
+
git clean -fd
|
|
234
|
+
|
|
235
|
+
# Then update
|
|
236
|
+
bash update.sh --force
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Script Comparison
|
|
242
|
+
|
|
243
|
+
| Feature | install.sh | update.sh |
|
|
244
|
+
|---------|------------|-----------|
|
|
245
|
+
| Clone repository | ✅ Yes | ❌ No (already exists) |
|
|
246
|
+
| Install dependencies | ✅ Yes | ✅ Yes |
|
|
247
|
+
| Setup token | ✅ Interactive | ❌ No |
|
|
248
|
+
| Force mode | ✅ Overwrite | ✅ Reinstall |
|
|
249
|
+
| Find installation | ❌ Specify type | ✅ Auto-detect |
|
|
250
|
+
| Show changelog | ❌ No | ✅ Optional |
|
|
251
|
+
| Verify installation | ✅ Yes | ✅ Yes |
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Best Practices
|
|
256
|
+
|
|
257
|
+
### For Users
|
|
258
|
+
|
|
259
|
+
1. **Initial install:** Use `install.sh`
|
|
260
|
+
2. **Updates:** Use `update.sh --changelog` to see what changed
|
|
261
|
+
3. **Token setup:** Easiest to do during interactive install
|
|
262
|
+
4. **Global vs Local:**
|
|
263
|
+
- Global: One install, all projects
|
|
264
|
+
- Local: Per-project, can use different versions
|
|
265
|
+
|
|
266
|
+
### For Developers
|
|
267
|
+
|
|
268
|
+
1. **Development:** Use `npm run install:local` for linking
|
|
269
|
+
2. **Testing changes:** Edit files, run tests, then reinstall
|
|
270
|
+
3. **Publish:** Use `npm publish`, then users can update
|
|
271
|
+
|
|
272
|
+
### Production Deployments
|
|
273
|
+
|
|
274
|
+
For team deployments:
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
#!/bin/bash
|
|
278
|
+
# deploy-forloop.sh
|
|
279
|
+
|
|
280
|
+
# Install globally on all team machines
|
|
281
|
+
curl -fsSL https://raw.githubusercontent.com/forloop-cc/forloop-opencode-plugin/main/install.sh | bash -s -- --global
|
|
282
|
+
|
|
283
|
+
# Set token (from secret manager)
|
|
284
|
+
export TOKEN=$(aws secretsmanager get-secret-value --secret-id forloop-token)
|
|
285
|
+
forloopTokenSet --token $TOKEN
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## Script Locations
|
|
291
|
+
|
|
292
|
+
| Location | Purpose |
|
|
293
|
+
|----------|---------|
|
|
294
|
+
| [install.sh](../install.sh) | Installation script |
|
|
295
|
+
| [update.sh](../update.sh) | Update script |
|
|
296
|
+
| [QUICKSTART-NON-DEV.md](QUICKSTART-NON-DEV.md) | User setup guide |
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Getting Help
|
|
301
|
+
|
|
302
|
+
- **Issues:** [GitHub Issues](https://github.com/forloop-cc/forloop-opencode-plugin/issues)
|
|
303
|
+
- **Documentation:** [docs/](../docs/)
|
|
304
|
+
- **Quick Start:** [QUICKSTART-NON-DEV.md](QUICKSTART-NON-DEV.md)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Planner Agent Skill Improvements
|
|
2
|
+
|
|
3
|
+
## Issues & Fixes
|
|
4
|
+
|
|
5
|
+
### 1. Plugin Folder Structure ✅ VERIFIED
|
|
6
|
+
|
|
7
|
+
**Current Implementation** (lambda-handler.mjs:58-66):
|
|
8
|
+
```javascript
|
|
9
|
+
function copyPluginRuntimeAssets(homeDir) {
|
|
10
|
+
copyDirRecursive('/var/task/forloop-opencode-plugin-planner/agent', runtimeAgentDir);
|
|
11
|
+
copyDirRecursive('/var/task/forloop-opencode-plugin-planner/skills', runtimeSkillsDir);
|
|
12
|
+
copyDirRecursive('/var/task/forloop-opencode-plugin-planner/plugins', runtimePluginsDir);
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**Target Locations**:
|
|
17
|
+
- Agents: `$HOME/.config/opencode/agent/` ✓ (opencode expects `agent/` not `agents/`)
|
|
18
|
+
- Skills: `$HOME/.config/opencode/skills/` ✓
|
|
19
|
+
- Plugins: `$HOME/.config/opencode/plugins/` ✓
|
|
20
|
+
|
|
21
|
+
**✅ Status**: Copied correctly! The opencode runtime uses `agent/` (singular) not `agents/`.
|
|
22
|
+
|
|
23
|
+
### 2. Agent Selection (ID vs Name) ⚠️ NEEDS FIX
|
|
24
|
+
|
|
25
|
+
**Current** (lambda-handler.mjs:439):
|
|
26
|
+
```javascript
|
|
27
|
+
const args = ['run', '--agent', agentId, '--', prompt];
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Opencode expects**: Agent name (from agent definition), not ID
|
|
31
|
+
|
|
32
|
+
**Fix**:
|
|
33
|
+
```javascript
|
|
34
|
+
// Use agent name from agent definition
|
|
35
|
+
const args = ['run', '--agent', agentName, '--', prompt];
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Agent Definition** (forLoopPlanner.md):
|
|
39
|
+
```markdown
|
|
40
|
+
---
|
|
41
|
+
id: forLoopPlanner
|
|
42
|
+
name: ForLoop Planner ← THIS should be passed
|
|
43
|
+
---
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 3. S3 Sync on Startup ❌ MISSING
|
|
47
|
+
|
|
48
|
+
**Problem**: `forloop-context` skill only checks local `.forloop/`, doesn't sync from S3 first
|
|
49
|
+
|
|
50
|
+
**Fix**: Update `forloop-context` skill to:
|
|
51
|
+
```typescript
|
|
52
|
+
1. Check if .forloop/manifest.json exists
|
|
53
|
+
2. If NOT exists or empty:
|
|
54
|
+
- Call forloopSprintList to get sprints
|
|
55
|
+
- Call forloopSyncS3ToLocal to sync latest context
|
|
56
|
+
3. Load context files
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 4. Story Creation with Doc Folder Link ❌ MISSING
|
|
60
|
+
|
|
61
|
+
**Problem**: `task-tracking` skill creates stories but doesn't link to doc_folder
|
|
62
|
+
|
|
63
|
+
**Fix**: Update `story-creation` and `task-tracking` skills:
|
|
64
|
+
```typescript
|
|
65
|
+
1. Before creating stories, get doc_folder ID
|
|
66
|
+
2. Pass storyId: docFolderId to story creation
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 5. task.md Updates ❌ NOT TRACKED
|
|
70
|
+
|
|
71
|
+
**Problem**: After stories created, task.md not updated with story IDs
|
|
72
|
+
|
|
73
|
+
**Fix**: Update `task-tracking` skill to:
|
|
74
|
+
```typescript
|
|
75
|
+
1. After story creation, update task.md with:
|
|
76
|
+
- Story IDs
|
|
77
|
+
- Story titles
|
|
78
|
+
- Status (todo/in_progress/done)
|
|
79
|
+
2. Upload updated task.md to S3
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Implementation Checklist
|
|
83
|
+
|
|
84
|
+
- [ ] Fix Lambda agent invocation (pass name not id)
|
|
85
|
+
- [ ] Update forloop-context skill (sync from S3)
|
|
86
|
+
- [ ] Update task-tracking skill (link doc_folder, update task.md)
|
|
87
|
+
- [ ] Update story-creation tool (accept storyId for linking)
|
|
88
|
+
- [ ] Test end-to-end flow
|