@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.
Files changed (55) hide show
  1. package/CHANGELOG.md +225 -0
  2. package/CODE_OF_CONDUCT.md +77 -0
  3. package/CONTRIBUTING.md +176 -0
  4. package/LICENSE +21 -0
  5. package/README.md +211 -0
  6. package/SECURITY.md +69 -0
  7. package/docs/CONFIGURATION.md +283 -0
  8. package/docs/DEVELOPER-VS-USER.md +129 -0
  9. package/docs/IMPROVED-AUTHENTICATION.md +317 -0
  10. package/docs/INSTALLATION-SCRIPTS.md +304 -0
  11. package/docs/PLANNER-AGENT-IMPROVEMENTS.md +88 -0
  12. package/docs/PLUGIN-ARCHITECTURE.md +308 -0
  13. package/docs/QUICKSTART-NON-DEV.md +94 -0
  14. package/docs/README-FOR-HUMANS-AND-AI.md +109 -0
  15. package/docs/README.md +70 -0
  16. package/docs/SKILLS-GAP-ANALYSIS.md +157 -0
  17. package/docs/USER-INTERACTION-MODEL.md +106 -0
  18. package/docs/file-management/2026-04-12-forloop-aivy-documents-sync.md +395 -0
  19. package/docs/file-management/FILE_UPLOAD_ENHANCEMENT.md +431 -0
  20. package/docs/file-management/FILE_UPLOAD_FLOW.md +300 -0
  21. package/docs/images/forloop-opencode-flow.png +0 -0
  22. package/docs/images/forloop-opencode-header.png +0 -0
  23. package/docs/superpowers/plans/2026-05-03-sprint-isolated-directory-structure.md +1450 -0
  24. package/docs/superpowers/plans/2026-05-29-install-system.md +850 -0
  25. package/docs/superpowers/specs/2026-05-03-sprint-isolated-directory-structure-design.md +149 -0
  26. package/docs/superpowers/specs/2026-05-19-opencode-message-recording-design.md +468 -0
  27. package/docs/superpowers/specs/2026-05-29-install-system-design.md +135 -0
  28. package/install.sh +317 -0
  29. package/package.json +87 -0
  30. package/plugins/capabilities/api-client.ts +556 -0
  31. package/plugins/capabilities/auth.ts +120 -0
  32. package/plugins/capabilities/config.ts +195 -0
  33. package/plugins/capabilities/context-resolver.ts +106 -0
  34. package/plugins/capabilities/token-storage.ts +98 -0
  35. package/plugins/forloop-plugin.ts +186 -0
  36. package/plugins/hooks/message-recorder.ts +258 -0
  37. package/plugins/hooks/shell-env.ts +62 -0
  38. package/plugins/tools/agent-sprint-tools.ts +100 -0
  39. package/plugins/tools/agent-suggestion-tools.ts +275 -0
  40. package/plugins/tools/agent-tools.ts +114 -0
  41. package/plugins/tools/ai-trigger-tools.ts +79 -0
  42. package/plugins/tools/developer-status-tool.ts +97 -0
  43. package/plugins/tools/file-tools.ts +240 -0
  44. package/plugins/tools/folder-tools.ts +75 -0
  45. package/plugins/tools/organization-tools.ts +213 -0
  46. package/plugins/tools/schedule-tools.ts +173 -0
  47. package/plugins/tools/sprint-tools.ts +287 -0
  48. package/plugins/tools/story-tools.ts +320 -0
  49. package/plugins/tools/sync-tools.ts +509 -0
  50. package/plugins/tools/template-tools.ts +170 -0
  51. package/plugins/tools/user-tools.ts +146 -0
  52. package/scripts/migrate-tokens.js +90 -0
  53. package/scripts/use-prod.sh +11 -0
  54. package/tsconfig.json +17 -0
  55. package/update.sh +172 -0
@@ -0,0 +1,157 @@
1
+ # Skills Gap Analysis & Improvements
2
+
3
+ ## Current State Analysis
4
+
5
+ ### ✅ What Skills Document Well
6
+
7
+ | Skill | Documented Workflow | Status |
8
+ |-------|-------------------|--------|
9
+ | `forloop-context` | Session startup, S3 sync (Step 7) | ✅ Documented |
10
+ | `task-tracking` | Create stories → Write task.md → Upload S3 with doc_folder | ✅ Documented |
11
+ | `plan-documentation` | Create plan → Upload S3 with doc_folder | ✅ Documented |
12
+ | `knowledge-management` | Capture knowledge → Upload S3 with doc_folder | ✅ Documented |
13
+ | `aivy-documents-sync` | Session start sync, post-change sync | ✅ Documented |
14
+
15
+ ### ❌ What Agent Actually Does (Problems)
16
+
17
+ **The agent definition (`forLoopPlanner.md`) is the PROBLEM.** It has its own simplified workflow that SKIPS critical steps documented in the skills:
18
+
19
+ | Expected (from Skills) | Agent Does (from Definition) | Gap |
20
+ |------------------------|------------------------------|-----|
21
+ | Sync S3 → local on session start | Only loads local `.forloop/` | ❌ Missing |
22
+ | Create/verify doc_folder before uploads | No mention of doc_folder | ❌ Missing |
23
+ | Upload task.md to S3 with `--storyId` | "Upload task file to S3" (no doc_folder) | ❌ Incomplete |
24
+ | Upload plan.md to S3 with `--storyId` | "Upload to S3" (no doc_folder) | ❌ Incomplete |
25
+ | Upload knowledge to S3 with `--storyId` | No knowledge upload mentioned | ❌ Missing |
26
+ | Verify uploads with `forloopFileList` | No verification step | ❌ Missing |
27
+
28
+ ## Root Cause
29
+
30
+ **The agent definition is the source of truth for the LLM**, not the skills. The skills provide detailed workflows, but the agent definition gives the high-level instructions. If the agent definition doesn't include a step, the LLM will skip it.
31
+
32
+ ## Required Improvements
33
+
34
+ ### 1. Agent Definition (`agent/forLoopPlanner.md`)
35
+
36
+ **Add to Session Startup Flow:**
37
+ ```markdown
38
+ ### Step 0.5: Sync from S3 (MANDATORY)
39
+
40
+ After loading local context, ALWAYS sync from S3:
41
+
42
+ ```bash
43
+ forloopSyncAivyFolder --sprintId {sprintId}
44
+ forloopSyncS3ToLocal --sprintId {sprintId}
45
+ ```
46
+
47
+ This ensures you have the latest plan, task, and knowledge files from the team.
48
+ ```
49
+
50
+ **Add to Workflow:**
51
+ ```markdown
52
+ ### Doc Folder Management (ALWAYS BEFORE UPLOADS)
53
+
54
+ Before uploading ANY file to S3:
55
+
56
+ 1. Ensure doc_folder exists:
57
+ ```bash
58
+ forloopSyncAivyFolder --sprintId {sprintId}
59
+ ```
60
+
61
+ 2. Get doc_folder story ID:
62
+ ```bash
63
+ forloopAivyDocGet --sprintId {sprintId}
64
+ ```
65
+
66
+ 3. Upload with linking:
67
+ ```bash
68
+ forloopSyncLocalToS3 \
69
+ --filePath {path} \
70
+ --sprintId {sprintId} \
71
+ --folder project/{plans,tasks,knowledge} \
72
+ --storyId {docFolderId}
73
+ ```
74
+
75
+ 4. Verify upload:
76
+ ```bash
77
+ forloopFileList --sprintId {sprintId}
78
+ ```
79
+ ```
80
+
81
+ ### 2. Sync Tools (`plugins/tools/sync-tools.ts`)
82
+
83
+ **Verify `forloopSyncAivyFolder` tool:**
84
+ - Checks if "Aivy Plan Doc" doc_folder exists
85
+ - Creates it if not
86
+ - Returns the doc_folder story ID
87
+
88
+ **Verify `forloopSyncS3ToLocal` tool:**
89
+ - Downloads all files from S3 `project/plans/`, `project/tasks/`, `project/knowledge/`
90
+ - Saves to `~/.forloop/plan/`, `~/.forloop/task/`, `~/.forloop/knowledge/`
91
+ - Updates manifest.json
92
+
93
+ **Verify `forloopSyncLocalToS3` tool:**
94
+ - Uploads file to correct S3 folder
95
+ - Links to doc_folder via `storyId` parameter
96
+ - Returns upload confirmation
97
+
98
+ ### 3. Skill Improvements
99
+
100
+ **forloop-context/SKILL.md:**
101
+ - Make Step 7 (S3 sync) more prominent
102
+ - Add explicit commands with parameters
103
+ - Add error handling for sync failures
104
+
105
+ **task-tracking/SKILL.md:**
106
+ - Already well-documented, but add verification checklist
107
+ - Emphasize doc_folder linking as MANDATORY
108
+
109
+ **plan-documentation/SKILL.md:**
110
+ - Already well-documented, but add verification checklist
111
+ - Emphasize doc_folder linking as MANDATORY
112
+
113
+ ## Implementation Priority
114
+
115
+ 1. **HIGH**: Update agent definition (forLoopPlanner.md) - This is the LLM's primary instructions
116
+ 2. **HIGH**: Verify sync tools implement doc_folder workflow correctly
117
+ 3. **MEDIUM**: Update skills to be more explicit about mandatory steps
118
+ 4. **LOW**: Add verification checklists to all skills
119
+
120
+ ## Expected Behavior After Fix
121
+
122
+ ### Session Start
123
+ ```
124
+ 1. Load local .forloop/ context
125
+ 2. Sync from S3 → local (get latest files)
126
+ 3. Present combined context summary
127
+ 4. Confirm sprint with user
128
+ ```
129
+
130
+ ### Creating Plan
131
+ ```
132
+ 1. Write plan to ~/.forloop/plan/
133
+ 2. Update manifest.json
134
+ 3. Ensure doc_folder exists (create if needed)
135
+ 4. Get doc_folder ID
136
+ 5. Upload plan to S3 with --storyId {docFolderId}
137
+ 6. Verify upload with forloopFileList
138
+ ```
139
+
140
+ ### Creating Stories
141
+ ```
142
+ 1. Write task.md to ~/.forloop/task/
143
+ 2. Update manifest.json
144
+ 3. Ensure doc_folder exists (should already exist from plan)
145
+ 4. Get doc_folder ID
146
+ 5. Upload task.md to S3 with --storyId {docFolderId}
147
+ 6. Verify upload with forloopFileList
148
+ ```
149
+
150
+ ### Capturing Knowledge
151
+ ```
152
+ 1. Write knowledge file to ~/.forloop/knowledge/
153
+ 2. Ensure doc_folder exists
154
+ 3. Get doc_folder ID
155
+ 4. Upload to S3 with --storyId {docFolderId}
156
+ 5. Verify upload with forloopFileList
157
+ ```
@@ -0,0 +1,106 @@
1
+ # How Users Interact with ForLoop Plugin
2
+
3
+ ## Understanding the Architecture
4
+
5
+ The ForLoop Plugin is **NOT a CLI tool** that you run directly. It's an **opencode plugin** that extends opencode's capabilities.
6
+
7
+ ### ❌ What Users DON'T Do
8
+
9
+ ```bash
10
+ # These DON'T work:
11
+ node plugins/tools/sprint-tools.ts ✗
12
+ npm run forloopSprintList ✗
13
+ ./plugins/forloop-plugin.ts ✗
14
+ ```
15
+
16
+ ### ✅ What Users DO Instead
17
+
18
+ Users interact through **opencode chat** using tool commands:
19
+
20
+ ```bash
21
+ # 1. Start opencode
22
+ opencode
23
+
24
+ # 2. In the chat, use tool commands:
25
+ forloopSprintList
26
+ forloopStoryCreate --title "As a user, I want to login" --sprintId 14
27
+ forloopAgentBreakdown --storyId 78
28
+ ```
29
+
30
+ ## Execution Flow
31
+
32
+ ```
33
+ ┌─────────────┐ ┌──────────────┐ ┌─────────────┐
34
+ │ User │ │ opencode │ │ ForLoop │
35
+ │ │ │ │ │ Plugin │
36
+ └──────┬──────┘ └──────┬───────┘ └──────┬──────┘
37
+ │ │ │
38
+ │ 1. Type command │ │
39
+ │───────────────────>│ │
40
+ │ │ │
41
+ │ │ 2. Route to plugin │
42
+ │ │─────────────────────>│
43
+ │ │ │
44
+ │ │ │ 3. Execute
45
+ │ │ │ (TypeScript code)
46
+ │ │ │
47
+ │ │ 4. Return result │
48
+ │ │<─────────────────────│
49
+ │ │ │
50
+ │ 5. Show output │ │
51
+ │<───────────────────│ │
52
+ │ │ │
53
+ ```
54
+
55
+ ## Tool Commands vs TypeScript Functions
56
+
57
+ | TypeScript Function | User Command |
58
+ |---------------------|--------------|
59
+ | `createSprintListTool()` | `forloopSprintList` |
60
+ | `createStoryCreateTool()` | `forloopStoryCreate --title "..."` |
61
+ | `createAgentBreakdownTool()` | `forloopAgentBreakdown --storyId 78` |
62
+
63
+ ## For Developers
64
+
65
+ If you're **developing** the plugin:
66
+
67
+ ```bash
68
+ # 1. Make changes to TypeScript files
69
+ edit plugins/tools/sprint-tools.ts
70
+
71
+ # 2. Run tests
72
+ npm run test:unit
73
+
74
+ # 3. Install locally to test
75
+ npm run install:local
76
+
77
+ # 4. Test in opencode
78
+ opencode
79
+ > forloopSprintList
80
+ ```
81
+
82
+ If you're **using** the plugin:
83
+
84
+ ```bash
85
+ # Just use opencode chat
86
+ opencode
87
+ > forloopSprintList
88
+
89
+ # That's it! No TypeScript knowledge needed.
90
+ ```
91
+
92
+ ## Summary
93
+
94
+ | Aspect | Developer | End User |
95
+ |--------|-----------|----------|
96
+ | Touches TypeScript? | ✅ Yes | ❌ No |
97
+ | Runs `npm` commands? | ✅ Yes | ❌ No |
98
+ | Uses `forloop.*` commands? | ✅ Yes | ✅ Yes |
99
+ | Needs to understand plugin architecture? | ✅ Yes | ❌ No |
100
+
101
+ **End users only need to know:**
102
+ 1. Install the plugin
103
+ 2. Set up API token
104
+ 3. Use `forloop.*` commands in opencode chat
105
+
106
+ That's it!
@@ -0,0 +1,395 @@
1
+ # ForLoop Aivy Documents - Auto-Sync Implementation Plan
2
+
3
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
+
5
+ **Goal:** Implement automatic bidirectional file synchronization between local `~/.forloop/` folder and S3, with auto-creation of "ForLoop Aivy Documents" doc_folder for organized file management.
6
+
7
+ **Architecture:** Enhance existing skills with sync capabilities - extends forloop-context skill for S3→local sync at session start, and enhances knowledge-management/plan-documentation/task-tracking skills for local→S3 sync on file changes.
8
+
9
+ **Tech Stack:** TypeScript, ForLoop plugin tools, AWS S3, Express.js backend
10
+
11
+ ---
12
+
13
+ ## Requirements Summary
14
+
15
+ Based on user requirements:
16
+
17
+ 1. **Doc Folder Auto-Creation**: Agent checks if doc_folder "ForLoop Aivy Documents" exists in working sprint, creates if not
18
+ 2. **S3 → Local Sync**: At session start (after manifest.json confirms active sprint), sync files from S3 to local `~/.forloop/`
19
+ 3. **Local → S3 Sync**: Immediate sync whenever files are created/updated/removed under `~/.forloop/*`
20
+ 4. **S3 Structure**: Keep current structure: `sprint/{id}/project/{plans,knowledge,tasks}/`
21
+
22
+ ---
23
+
24
+ ## File Structure
25
+
26
+ ### New Files to Create
27
+
28
+ 1. **Skill:** `forloop-opencode-plugin-planner/skills/aivy-documents-sync/SKILL.md`
29
+ - Auto-sync skill for bidirectional synchronization
30
+ - Integrates with forloop-context for session startup
31
+ - Handles doc_folder creation and file tracking
32
+
33
+ 2. **Plugin Tool:** `forloop-opencode-plugin-planner/plugins/tools/sync-tools.ts`
34
+ - `createSyncTool()` - Main sync orchestration
35
+ - `createDocFolderCheckTool()` - Auto-create doc_folder
36
+ - Helper functions for file comparison
37
+
38
+ 3. **Test File:** `forloop-opencode-plugin-planner/test/suites/integration/sync-api.test.ts`
39
+ - Integration tests for sync functionality
40
+
41
+ ### Modified Files
42
+
43
+ 1. **forloop-context/SKILL.md** - Add sync step after loading manifest
44
+ 2. **knowledge-management/SKILL.md** - Add sync trigger after file creation
45
+ 3. **plan-documentation/SKILL.md** - Add sync trigger after file creation
46
+ 4. **task-tracking/SKILL.md** - Add sync trigger after file creation
47
+ 5. **file-tools.ts** - Add sync tracking capabilities
48
+ 6. **api-client.ts** - Add file comparison/download methods
49
+
50
+ ---
51
+
52
+ ## Implementation Tasks
53
+
54
+ ### Task 1: Create Sync Tools Plugin
55
+
56
+ **Files:**
57
+ - Create: `forloop-opencode-plugin-planner/plugins/tools/sync-tools.ts`
58
+ - Modify: `forloop-opencode-plugin-planner/plugins/forloop-plugin.ts:106-108`
59
+ - Test: `forloop-opencode-plugin-planner/test/suites/unit/sync-tools.test.ts`
60
+
61
+ - [ ] **Step 1: Create sync-tools.ts with doc_folder check tool**
62
+
63
+ ```typescript
64
+ import { tool } from '@opencode-ai/plugin';
65
+ import { ForLoopAPIClient } from '../capabilities/api-client';
66
+ import { validateToken } from '../capabilities/auth';
67
+ import { resolveSprintId } from '../capabilities/context-resolver';
68
+
69
+ export function createDocFolderCheckTool(client: ForLoopAPIClient) {
70
+ return tool({
71
+ description: 'Check and auto-create "ForLoop Aivy Documents" doc_folder in sprint',
72
+ args: {
73
+ sprintId: tool.schema.number()
74
+ .optional()
75
+ .describe('Target sprint ID (auto-detected from context)'),
76
+ },
77
+ async execute(args, context) {
78
+ const tokenResult = await validateToken();
79
+ if (!tokenResult.valid) {
80
+ return tokenResult.error;
81
+ }
82
+ client.setToken?.(tokenResult.token);
83
+
84
+ try {
85
+ // Resolve sprint ID
86
+ const resolution = await resolveSprintId(args.sprintId, context.directory);
87
+ if (!resolution.sprintId) {
88
+ return '❌ No sprint ID available. Please select a sprint first.';
89
+ }
90
+
91
+ // Get sprint details including stories
92
+ const sprint = await client.getSprint(resolution.sprintId);
93
+
94
+ // Check if "ForLoop Aivy Documents" doc_folder exists
95
+ const docFolderStory = sprint.stories?.find((story: any) =>
96
+ story.type === 'doc_folder' &&
97
+ story.title === 'ForLoop Aivy Documents'
98
+ );
99
+
100
+ if (docFolderStory) {
101
+ return `✅ "ForLoop Aivy Documents" folder already exists (Story #${docFolderStory.id})`;
102
+ }
103
+
104
+ // Create doc_folder if not exists
105
+ const newFolder = await client.createStory({
106
+ title: 'ForLoop Aivy Documents',
107
+ description: ' Auto-created folder for ForLoop Aivy planning documents and sync',
108
+ sprintId: resolution.sprintId,
109
+ type: 'doc_folder',
110
+ metadata: JSON.stringify({
111
+ permissions: 'team',
112
+ autoCreated: true,
113
+ purpose: 'aivy-sync',
114
+ }),
115
+ status: 'todo',
116
+ });
117
+
118
+ return `✅ Created "ForLoop Aivy Documents" folder (Story #${newFolder.id})`;
119
+ } catch (error: any) {
120
+ return `❌ Error: ${error.message}`;
121
+ }
122
+ },
123
+ });
124
+ }
125
+ ```
126
+
127
+ - [ ] **Step 2: Add createS3ToLocalSyncTool function**
128
+
129
+ ```typescript
130
+ export function createS3ToLocalSyncTool(client: ForLoopAPIClient) {
131
+ return tool({
132
+ description: 'Sync files from S3 to local ~/.forloop/ folder',
133
+ args: {
134
+ sprintId: tool.schema.number()
135
+ .optional()
136
+ .describe('Target sprint ID'),
137
+ syncKnowledge: tool.schema.boolean()
138
+ .default(true)
139
+ .describe('Sync knowledge files'),
140
+ syncPlans: tool.schema.boolean()
141
+ .default(true)
142
+ .describe('Sync plan files'),
143
+ syncTasks: tool.schema.boolean()
144
+ .default(true)
145
+ .describe('Sync task files'),
146
+ },
147
+ async execute(args, context) {
148
+ const tokenResult = await validateToken();
149
+ if (!tokenResult.valid) {
150
+ return tokenResult.error;
151
+ }
152
+ client.setToken?.(tokenResult.token);
153
+
154
+ try {
155
+ const resolution = await resolveSprintId(args.sprintId, context.directory);
156
+ if (!resolution.sprintId) {
157
+ return '❌ No sprint ID available.';
158
+ }
159
+
160
+ // Get files from S3
161
+ const s3Files = await client.getSprintFiles(resolution.sprintId);
162
+
163
+ // Filter files by folder pattern
164
+ const knowledgeFiles = s3Files.filter((f: any) =>
165
+ f.url?.includes('/project/knowledge/')
166
+ );
167
+ const planFiles = s3Files.filter((f: any) =>
168
+ f.url?.includes('/project/plans/')
169
+ );
170
+ const taskFiles = s3Files.filter((f: any) =>
171
+ f.url?.includes('/project/tasks/')
172
+ );
173
+
174
+ // Download and save locally
175
+ const homeDir = process.env.HOME || '/tmp/home';
176
+ let syncedCount = 0;
177
+
178
+ if (args.syncKnowledge) {
179
+ for (const file of knowledgeFiles) {
180
+ const downloadUrl = await client.getFileOpenUrl(file.id);
181
+ const fileName = file.originalName || file.filename;
182
+ // Save to ~/.forloop/knowledge/
183
+ // Increment syncedCount
184
+ }
185
+ }
186
+
187
+ // Repeat for plans and tasks...
188
+
189
+ return `✅ Synced ${syncedCount} files from S3 to ~/.forloop/`;
190
+ } catch (error: any) {
191
+ return `❌ Error: ${error.message}`;
192
+ }
193
+ },
194
+ });
195
+ }
196
+ ```
197
+
198
+ - [ ] **Step 3: Add createLocalToS3SyncTool function**
199
+
200
+ ```typescript
201
+ export function createLocalToS3SyncTool(client: ForLoopAPIClient) {
202
+ return tool({
203
+ description: 'Sync local ~/.forloop/ files to S3',
204
+ args: {
205
+ filePath: tool.schema.string()
206
+ .describe('Local file path to sync'),
207
+ sprintId: tool.schema.number()
208
+ .optional()
209
+ .describe('Target sprint ID'),
210
+ },
211
+ async execute(args, context) {
212
+ // Implementation for immediate sync of individual files
213
+ // Used by knowledge-management, plan-documentation, task-tracking skills
214
+ },
215
+ });
216
+ }
217
+ ```
218
+
219
+ - [ ] **Step 4: Register tools in forloop-plugin.ts**
220
+
221
+ **File:** `forloop-opencode-plugin-planner/plugins/forloop-plugin.ts`
222
+
223
+ **Locate lines 106-108:**
224
+ ```typescript
225
+ 'forloopFileUpload': createFileUploadTool(client),
226
+ 'forloopFileList': createFileListTool(client),
227
+ ```
228
+
229
+ **Add after file tools:**
230
+ ```typescript
231
+ 'forloop.sync.folder': createDocFolderCheckTool(client),
232
+ 'forloopSyncS3ToLocal': createS3ToLocalSyncTool(client),
233
+ 'forloopSyncLocalToS3': createLocalToS3SyncTool(client),
234
+ ```
235
+
236
+ - [ ] **Step 5: Write unit tests**
237
+
238
+ **File:** `forloop-opencode-plugin-planner/test/suites/unit/sync-tools.test.ts`
239
+
240
+ ```typescript
241
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
242
+ import {
243
+ createDocFolderCheckTool,
244
+ createS3ToLocalSyncTool,
245
+ createLocalToS3SyncTool,
246
+ } from '../../../plugins/tools/sync-tools';
247
+
248
+ describe('Sync Tools', () => {
249
+ const mockClient = {
250
+ getSprint: vi.fn(),
251
+ createStory: vi.fn(),
252
+ getSprintFiles: vi.fn(),
253
+ getFileOpenUrl: vi.fn(),
254
+ // ... other mocks
255
+ };
256
+
257
+ describe('forloop.sync.folder', () => {
258
+ it('should detect existing doc_folder', async () => {
259
+ mockClient.getSprint.mockResolvedValue({
260
+ id: 14,
261
+ stories: [
262
+ { id: 101, type: 'doc_folder', title: 'ForLoop Aivy Documents' }
263
+ ]
264
+ });
265
+
266
+ const tool = createDocFolderCheckTool(mockClient as any);
267
+ const result = await tool.executor({ sprintId: 14 }, { directory: '.' });
268
+
269
+ expect(result).toContain('already exists');
270
+ expect(mockClient.createStory).not.toHaveBeenCalled();
271
+ });
272
+
273
+ it('should create doc_folder if not exists', async () => {
274
+ mockClient.getSprint.mockResolvedValue({
275
+ id: 14,
276
+ stories: []
277
+ });
278
+
279
+ mockClient.createStory.mockResolvedValue({
280
+ id: 102,
281
+ title: 'ForLoop Aivy Documents',
282
+ type: 'doc_folder'
283
+ });
284
+
285
+ const tool = createDocFolderCheckTool(mockClient as any);
286
+ const result = await tool.executor({ sprintId: 14 }, { directory: '.' });
287
+
288
+ expect(result).toContain('Created');
289
+ expect(mockClient.createStory).toHaveBeenCalledWith(expect.objectContaining({
290
+ title: 'ForLoop Aivy Documents',
291
+ type: 'doc_folder'
292
+ }));
293
+ });
294
+ });
295
+ });
296
+ ```
297
+
298
+ - [ ] **Step 6: Run tests**
299
+
300
+ ```bash
301
+ cd forloop-opencode-plugin-planner
302
+ npm run test:unit -- sync-tools
303
+ ```
304
+
305
+ Expected: All tests PASS
306
+
307
+ - [ ] **Step 7: Commit**
308
+
309
+ ```bash
310
+ git add plugins/tools/sync-tools.ts plugins/forloop-plugin.ts test/suites/unit/sync-tools.test.ts
311
+ git commit -m "feat: add ForLoop Aivy documents sync tools"
312
+ ```
313
+
314
+ ---
315
+
316
+ ### Task 2: Create Auto-Sync Skill
317
+
318
+ **Files:**
319
+ - Create: `forloop-opencode-plugin-planner/skills/aivy-documents-sync/SKILL.md`
320
+ - Modify: `forloop-opencode-plugin-planner/skills/forloop-context/SKILL.md:28-54`
321
+
322
+ - [ ] **Step 1: Create aivy-documents-sync skill**
323
+
324
+ Create comprehensive skill document (see full content in planning document) covering:
325
+ - Session startup sync workflow
326
+ - File change sync triggers
327
+ - Integration with existing skills
328
+ - Sync manifest tracking
329
+ - Error handling
330
+ - Conflict resolution
331
+
332
+ - [ ] **Step 2: Update forloop-context skill**
333
+
334
+ **File:** `forloop-opencode-plugin-planner/skills/forloop-context/SKILL.md`
335
+
336
+ Add Step 7 after "Present to user":
337
+ ```markdown
338
+ ### Step 7: Auto-Sync Files (NEW)
339
+ 1. Check and create doc_folder: `forloop.sync.folder --sprintId {id}`
340
+ 2. Sync S3 to local: `forloopSyncS3ToLocal --sprintId {id}`
341
+ 3. Report sync status
342
+ ```
343
+
344
+ - [ ] **Step 3: Update other skills**
345
+
346
+ Add sync tracking steps to:
347
+ - knowledge-management/SKILL.md (after upload)
348
+ - plan-documentation/SKILL.md (after upload)
349
+ - task-tracking/SKILL.md (after upload)
350
+
351
+ - [ ] **Step 4: Commit**
352
+
353
+ ```bash
354
+ git add skills/*.md
355
+ git commit -m "feat: add ForLoop Aivy auto-sync skill"
356
+ ```
357
+
358
+ ---
359
+
360
+ ### Task 3: Extend API Client
361
+
362
+ **Files:**
363
+ - Modify: `forloop-opencode-plugin-planner/plugins/capabilities/api-client.ts`
364
+
365
+ - [ ] **Step 1: Add downloadFile method**
366
+ - [ ] **Step 2: Add compareFiles method**
367
+ - [ ] **Step 3: Commit**
368
+
369
+ ---
370
+
371
+ ### Task 4: Write Integration Tests
372
+
373
+ **Files:**
374
+ - Create: `forloop-opencode-plugin-planner/test/suites/integration/sync-api.test.ts`
375
+
376
+ - [ ] **Step 1: Create test file**
377
+ - [ ] **Step 2: Run tests**
378
+ - [ ] **Step 3: Commit**
379
+
380
+ ---
381
+
382
+ ## Execution Handoff
383
+
384
+ **Plan complete. Two execution options:**
385
+
386
+ **1. Subagent-Driven (recommended)** - Fresh subagent per task, review between tasks, fast iteration
387
+
388
+ **2. Inline Execution** - Execute tasks in this session with checkpoints
389
+
390
+ **Which approach?**
391
+
392
+ ---
393
+
394
+ **Created:** 2026-04-12
395
+ **Version:** 1.0.0