@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,135 @@
|
|
|
1
|
+
# Install System Design
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-05-29
|
|
4
|
+
**Status:** Approved
|
|
5
|
+
**Context:** Designing public installation system for the forloop-opencode-plugin-planner before publishing to GitHub.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
Two-file install system at repo root: `install.sh` (one-liner installer) and `update.sh` (updater). Supports both git-clone and npm install methods, local and global install locations, and jq-based smart config merging that preserves existing opencode configuration.
|
|
10
|
+
|
|
11
|
+
## File Structure
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
forloop-opencode-plugin-planner/
|
|
15
|
+
├── install.sh # Main install script (curl-pipeable)
|
|
16
|
+
├── update.sh # Update script (curl-pipeable)
|
|
17
|
+
├── scripts/ # Utility scripts only (no install variants)
|
|
18
|
+
│ ├── migrate-tokens.js
|
|
19
|
+
│ └── use-prod.sh
|
|
20
|
+
└── package.json # npm package config
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Removed**: `scripts/install.sh`, `scripts/install-global.sh`, `scripts/install-local.sh`, `scripts/install-global.cjs`, `scripts/install-local.cjs` — all logic consolidated into root `install.sh`.
|
|
24
|
+
|
|
25
|
+
## install.sh
|
|
26
|
+
|
|
27
|
+
### One-Liner
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
curl -fsSL https://raw.githubusercontent.com/forloop-cc/forloop-opencode-plugin-planner/main/install.sh | bash
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### CLI Flags
|
|
34
|
+
|
|
35
|
+
| Flag | Behavior |
|
|
36
|
+
|------|----------|
|
|
37
|
+
| (none) | Interactive mode -- prompts for install type, location, token setup |
|
|
38
|
+
| `--global` / `-g` | Non-interactive global install to `~/.config/opencode/plugins/forloop-planner/` |
|
|
39
|
+
| `--local` / `-l` | Non-interactive local install to `./.opencode/plugins/forloop-planner/` |
|
|
40
|
+
| `--dir PATH` / `-d PATH` | Custom install directory |
|
|
41
|
+
| `--npm` | Use `npm install @forloop/opencode-plugin-planner` instead of `git clone` |
|
|
42
|
+
| `--branch NAME` | Clone specific branch (default: `main`, overridable via `FORLOOP_BRANCH` env var) |
|
|
43
|
+
| `--force` / `-f` | Overwrite existing installation |
|
|
44
|
+
| `--help` / `-h` | Show help |
|
|
45
|
+
|
|
46
|
+
### Piped Non-Interactive
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
curl -fsSL .../install.sh | bash -s -- --global
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Install Flow
|
|
53
|
+
|
|
54
|
+
1. **Dependency check**: git, node, npm, jq -- with platform-specific install instructions if missing
|
|
55
|
+
2. **OpenCode check**: Warn if `opencode` CLI not found, continue anyway (user may install later)
|
|
56
|
+
3. **Install location**: Resolve from flags or interactive prompt
|
|
57
|
+
4. **Clone or npm install**:
|
|
58
|
+
- Git: `git clone --depth 1 <repo> <dir>` for speed, then `npm install --omit=dev`
|
|
59
|
+
- npm: `npm install @forloop/opencode-plugin-planner` in target, adds `file://` path to config
|
|
60
|
+
5. **Config merge (jq)**: Smart-merges plugin path into `opencode.json` or `~/.config/opencode/config.json`
|
|
61
|
+
6. **Token setup** (interactive only): Guides user through creating and saving API token
|
|
62
|
+
7. **Verification**: Checks entry point `plugins/forloop-plugin.ts` exists
|
|
63
|
+
|
|
64
|
+
### Config Merging (jq)
|
|
65
|
+
|
|
66
|
+
Targets the config file opencode reads (`opencode.json` for project-level, `~/.config/opencode/config.json` for global). Logic:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
jq 'if .plugin then .plugin += ["file://<INSTALL_DIR>/forloop-opencode-plugin-planner"]
|
|
70
|
+
else . + {"plugin": ["file://<INSTALL_DIR>/forloop-opencode-plugin-planner"]}
|
|
71
|
+
end | unique' config.json > config.json.tmp
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
- Preserves all existing config keys
|
|
75
|
+
- Adds only the plugin entry
|
|
76
|
+
- Deduplicates the plugin array
|
|
77
|
+
- Backs up original before writing
|
|
78
|
+
|
|
79
|
+
## update.sh
|
|
80
|
+
|
|
81
|
+
### One-Liner
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
curl -fsSL https://raw.githubusercontent.com/forloop-cc/forloop-opencode-plugin-planner/main/update.sh | bash
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Auto-Detection Order
|
|
88
|
+
|
|
89
|
+
1. `--dir PATH` flag (explicit)
|
|
90
|
+
2. `FORLOOP_PLUGIN_DIR` env var
|
|
91
|
+
3. `./.opencode/plugins/forloop-planner/` (local)
|
|
92
|
+
4. `~/.config/opencode/plugins/forloop-planner/` (global)
|
|
93
|
+
|
|
94
|
+
### CLI Flags
|
|
95
|
+
|
|
96
|
+
| Flag | Behavior |
|
|
97
|
+
|------|----------|
|
|
98
|
+
| `--dir PATH` | Update specific install directory |
|
|
99
|
+
| `--force` / `-f` | Pull even if already up to date |
|
|
100
|
+
| `--changelog` / `-c` | Show recent CHANGELOG entries after update |
|
|
101
|
+
| `--help` / `-h` | Show help |
|
|
102
|
+
|
|
103
|
+
### Update Flow
|
|
104
|
+
|
|
105
|
+
1. Find existing installation (verify `.git` dir for git install, `package.json` for npm)
|
|
106
|
+
2. **Git install**: `git fetch`, compare local vs remote, `git pull` if behind, `npm install --omit=dev`
|
|
107
|
+
3. **npm install**: Run `npm update` inside directory
|
|
108
|
+
4. Show version change (old commit/tag → new)
|
|
109
|
+
5. Optionally print CHANGELOG.md changes
|
|
110
|
+
|
|
111
|
+
## npm Package Configuration
|
|
112
|
+
|
|
113
|
+
- **Name**: `@forloop/opencode-plugin-planner`
|
|
114
|
+
- **Version**: 2.2.0 (current)
|
|
115
|
+
- **Entry**: `./plugins/forloop-plugin.ts`
|
|
116
|
+
- **Files field**: Only distributable files (plugins/, skills/, agents/, scripts/, docs/, install.sh, update.sh, package.json, opencode.json, tsconfig.json, README.md, LICENSE, CHANGELOG.md) -- excludes test/, .github/
|
|
117
|
+
|
|
118
|
+
### npm Install (via `install.sh --npm`)
|
|
119
|
+
|
|
120
|
+
1. `npm install @forloop/opencode-plugin-planner`
|
|
121
|
+
2. `install.sh --npm` adds `file://./node_modules/@forloop/opencode-plugin-planner` to opencode config
|
|
122
|
+
3. Updates via `npm update` in the future
|
|
123
|
+
|
|
124
|
+
### Publishing (CI)
|
|
125
|
+
|
|
126
|
+
- Triggered by GitHub Release
|
|
127
|
+
- `.github/workflows/release.yml` runs `npm publish --access public`
|
|
128
|
+
- Git tag auto-created from `package.json` version
|
|
129
|
+
|
|
130
|
+
## Non-Goals
|
|
131
|
+
|
|
132
|
+
- No installer for the developer plugin (forloop-opencode-plugin-developer) — separate concern
|
|
133
|
+
- No migration from old install path (`forloop-opencode-plugin` or `forloop` dir names) — existing users can reinstall
|
|
134
|
+
- No auto-update daemon or hook
|
|
135
|
+
- No Windows-specific installer (Git Bash / WSL supported via bash)
|
package/install.sh
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
# ForLoop Plugin Installer
|
|
5
|
+
# https://github.com/forloop-cc/forloop-opencode-plugin-planner
|
|
6
|
+
#
|
|
7
|
+
# Adds the plugin to opencode.json. opencode handles downloading/caching.
|
|
8
|
+
#
|
|
9
|
+
# Usage:
|
|
10
|
+
# curl -fsSL https://raw.githubusercontent.com/forloop-cc/forloop-opencode-plugin-planner/main/install.sh | bash
|
|
11
|
+
# curl -fsSL ... | bash -s -- --global
|
|
12
|
+
# bash install.sh --global --npm # Install via npm package
|
|
13
|
+
# bash install.sh --local # Install for current project only
|
|
14
|
+
|
|
15
|
+
# ── Platform & colors ────────────────────────────────────────────────────────
|
|
16
|
+
PLATFORM="$(uname -s)"
|
|
17
|
+
case "$PLATFORM" in
|
|
18
|
+
Darwin*) PLATFORM_LABEL="macOS";;
|
|
19
|
+
Linux*) PLATFORM_LABEL="Linux";;
|
|
20
|
+
CYGWIN*|MINGW*|MSYS*) PLATFORM_LABEL="Windows";;
|
|
21
|
+
*) PLATFORM_LABEL="Unknown";;
|
|
22
|
+
esac
|
|
23
|
+
|
|
24
|
+
if [ "$PLATFORM_LABEL" = "Windows" ] && [ -z "$WT_SESSION" ] && [ -z "$ConEmuPID" ]; then
|
|
25
|
+
RED=''; GREEN=''; YELLOW=''; BLUE=''; CYAN=''; BOLD=''; NC=''
|
|
26
|
+
else
|
|
27
|
+
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
|
|
28
|
+
BLUE='\033[0;34m'; CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m'
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# ── Configuration ────────────────────────────────────────────────────────────
|
|
32
|
+
NPM_PACKAGE="@forloop-cc/forloop-opencode-plugin-planner"
|
|
33
|
+
GIT_URL="forloop-planner@git+https://github.com/forloop-cc/forloop-opencode-plugin-planner.git"
|
|
34
|
+
AGENTS_SKILLS_REPO="https://github.com/forloop-cc/forloop-agents-skills.git"
|
|
35
|
+
AGENTS_SKILLS_DIR="$HOME/.config/forloop/agents-skills"
|
|
36
|
+
|
|
37
|
+
INSTALL_TYPE="" # global | local
|
|
38
|
+
USE_NPM=false
|
|
39
|
+
SKIP_AGENTS=false
|
|
40
|
+
NON_INTERACTIVE=false
|
|
41
|
+
PROJECT_ROOT="$(pwd)"
|
|
42
|
+
|
|
43
|
+
print_header() { echo -e "${BLUE}${BOLD}╔══════════════════════════════════════════╗\n║ ForLoop Plugin Installer ║\n╚══════════════════════════════════════════╝${NC}\n"; }
|
|
44
|
+
print_success() { echo -e "${GREEN}✓${NC} $1"; }
|
|
45
|
+
print_info() { echo -e "${BLUE}ℹ${NC} $1"; }
|
|
46
|
+
print_warning() { echo -e "${YELLOW}⚠${NC} $1"; }
|
|
47
|
+
print_error() { echo -e "${RED}✗${NC} $1" >&2; }
|
|
48
|
+
print_step() { echo -e "\n${CYAN}${BOLD}▶${NC} $1\n"; }
|
|
49
|
+
|
|
50
|
+
show_help() {
|
|
51
|
+
cat << 'HELPEOF'
|
|
52
|
+
Usage: install.sh [OPTIONS]
|
|
53
|
+
|
|
54
|
+
Adds the ForLoop Plugin to your opencode configuration. opencode handles
|
|
55
|
+
downloading and caching the plugin on next startup. Also installs agents
|
|
56
|
+
and skills from forloop-agents-skills.
|
|
57
|
+
|
|
58
|
+
Options:
|
|
59
|
+
-g, --global Install globally (~/.config/opencode/opencode.json)
|
|
60
|
+
-l, --local Install for current project only (./opencode.json)
|
|
61
|
+
-n, --npm Use npm package (default: git URL from GitHub)
|
|
62
|
+
--skip-agents Skip installing agents and skills
|
|
63
|
+
-h, --help Show this help
|
|
64
|
+
|
|
65
|
+
Examples:
|
|
66
|
+
curl -fsSL .../install.sh | bash # Interactive (local by default)
|
|
67
|
+
curl -fsSL .../install.sh | bash -s -- -g # Global, non-interactive
|
|
68
|
+
bash install.sh --global --npm # Global via npm package
|
|
69
|
+
HELPEOF
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# ── Dependency checks ────────────────────────────────────────────────────────
|
|
73
|
+
|
|
74
|
+
check_jq() {
|
|
75
|
+
if ! command -v jq &>/dev/null; then
|
|
76
|
+
print_error "jq is required for config merging"
|
|
77
|
+
case "$PLATFORM_LABEL" in
|
|
78
|
+
macOS) echo " brew install jq" ;;
|
|
79
|
+
Linux) echo " sudo apt-get install jq (Ubuntu/Debian)"
|
|
80
|
+
echo " sudo dnf install jq (Fedora/RHEL)" ;;
|
|
81
|
+
Windows) echo " scoop install jq or https://stedolan.github.io/jq/download/" ;;
|
|
82
|
+
esac
|
|
83
|
+
return 1
|
|
84
|
+
fi
|
|
85
|
+
return 0
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
check_opencode() {
|
|
89
|
+
if command -v opencode &>/dev/null; then
|
|
90
|
+
print_success "opencode found: $(which opencode)"
|
|
91
|
+
else
|
|
92
|
+
print_warning "opencode CLI not found"
|
|
93
|
+
echo " Install: curl -fsSL https://opencode.ai/install.sh | bash"
|
|
94
|
+
if [ "$NON_INTERACTIVE" != true ]; then
|
|
95
|
+
read -p "Continue anyway? [y/N] " -r; echo
|
|
96
|
+
[[ ! $REPLY =~ ^[Yy]$ ]] && exit 1
|
|
97
|
+
fi
|
|
98
|
+
fi
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
check_all_deps() {
|
|
102
|
+
print_step "Checking dependencies..."
|
|
103
|
+
check_jq || exit 1
|
|
104
|
+
check_opencode
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
# ── Install location ─────────────────────────────────────────────────────────
|
|
108
|
+
|
|
109
|
+
get_config_file() {
|
|
110
|
+
if [ "$INSTALL_TYPE" = "global" ]; then
|
|
111
|
+
mkdir -p "$HOME/.config/opencode"
|
|
112
|
+
echo "$HOME/.config/opencode/opencode.json"
|
|
113
|
+
else
|
|
114
|
+
echo "$PROJECT_ROOT/opencode.json"
|
|
115
|
+
fi
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
# ── Plugin entry selection ───────────────────────────────────────────────────
|
|
119
|
+
|
|
120
|
+
get_plugin_entry() {
|
|
121
|
+
if [ "$USE_NPM" = true ]; then
|
|
122
|
+
echo "$NPM_PACKAGE"
|
|
123
|
+
else
|
|
124
|
+
echo "$GIT_URL"
|
|
125
|
+
fi
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
# ── Config merging ───────────────────────────────────────────────────────────
|
|
129
|
+
|
|
130
|
+
merge_plugin_into_config() {
|
|
131
|
+
local config_file
|
|
132
|
+
config_file="$(get_config_file)"
|
|
133
|
+
local plugin_entry
|
|
134
|
+
plugin_entry="$(get_plugin_entry)"
|
|
135
|
+
|
|
136
|
+
print_step "Updating opencode configuration..."
|
|
137
|
+
|
|
138
|
+
if [ ! -f "$config_file" ]; then
|
|
139
|
+
echo "{}" > "$config_file"
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
local backup="${config_file}.backup.$(date +%Y%m%d%H%M%S)"
|
|
143
|
+
cp "$config_file" "$backup"
|
|
144
|
+
|
|
145
|
+
local tmp
|
|
146
|
+
tmp="$(mktemp)"
|
|
147
|
+
|
|
148
|
+
jq --arg p "$plugin_entry" '
|
|
149
|
+
if .plugin then
|
|
150
|
+
.plugin += [$p] | .plugin |= unique
|
|
151
|
+
else
|
|
152
|
+
. + {"plugin": [$p]}
|
|
153
|
+
end
|
|
154
|
+
' "$config_file" > "$tmp"
|
|
155
|
+
|
|
156
|
+
if [ -s "$tmp" ]; then
|
|
157
|
+
mv "$tmp" "$config_file"
|
|
158
|
+
print_success "Plugin registered in: $config_file"
|
|
159
|
+
print_info "Backup saved: $backup"
|
|
160
|
+
else
|
|
161
|
+
print_error "Config merge produced empty file — restoring backup"
|
|
162
|
+
mv "$backup" "$config_file"
|
|
163
|
+
rm -f "$tmp"
|
|
164
|
+
exit 1
|
|
165
|
+
fi
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
# ── Agents & skills setup ────────────────────────────────────────────────────
|
|
169
|
+
|
|
170
|
+
setup_agents_skills() {
|
|
171
|
+
print_step "Setting up agents and skills..."
|
|
172
|
+
|
|
173
|
+
if [ ! -d "$AGENTS_SKILLS_DIR" ]; then
|
|
174
|
+
print_info "Cloning forloop-agents-skills..."
|
|
175
|
+
if ! git clone --depth 1 "https://github.com/forloop-cc/forloop-agents-skills.git" "$AGENTS_SKILLS_DIR" 2>&1; then
|
|
176
|
+
print_warning "Could not clone agents-skills repo (may not be public yet)"
|
|
177
|
+
return
|
|
178
|
+
fi
|
|
179
|
+
else
|
|
180
|
+
print_info "Updating forloop-agents-skills..."
|
|
181
|
+
cd "$AGENTS_SKILLS_DIR" && git pull origin main 2>/dev/null && cd - > /dev/null || true
|
|
182
|
+
fi
|
|
183
|
+
|
|
184
|
+
local config_dir
|
|
185
|
+
if [ "$INSTALL_TYPE" = "global" ]; then
|
|
186
|
+
config_dir="$HOME/.config/opencode"
|
|
187
|
+
else
|
|
188
|
+
config_dir="$PROJECT_ROOT/.opencode"
|
|
189
|
+
fi
|
|
190
|
+
|
|
191
|
+
local agents_dir="$config_dir/agents"
|
|
192
|
+
local skills_dir="$config_dir/skills"
|
|
193
|
+
mkdir -p "$agents_dir" "$skills_dir"
|
|
194
|
+
|
|
195
|
+
for agent_file in "$AGENTS_SKILLS_DIR/agents/"*.md; do
|
|
196
|
+
[ -f "$agent_file" ] || continue
|
|
197
|
+
local name
|
|
198
|
+
name="$(basename "$agent_file")"
|
|
199
|
+
ln -sf "$agent_file" "$agents_dir/$name"
|
|
200
|
+
print_success "Agent linked: $name"
|
|
201
|
+
done
|
|
202
|
+
|
|
203
|
+
for skill_dir in "$AGENTS_SKILLS_DIR/skills/"*/; do
|
|
204
|
+
[ -d "$skill_dir" ] || continue
|
|
205
|
+
local name
|
|
206
|
+
name="$(basename "$skill_dir")"
|
|
207
|
+
ln -sfn "$skill_dir" "$skills_dir/$name"
|
|
208
|
+
print_success "Skill linked: $name"
|
|
209
|
+
done
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
# ── Token setup ──────────────────────────────────────────────────────────────
|
|
213
|
+
|
|
214
|
+
setup_token() {
|
|
215
|
+
echo ""
|
|
216
|
+
print_step "Setting up API token..."
|
|
217
|
+
echo " Create a token at: https://forloop.cc/profile?tab=api-tokens"
|
|
218
|
+
echo " Scopes needed: sprint:read, sprint:write, story:read, story:write, agent:query, profile:read"
|
|
219
|
+
echo ""
|
|
220
|
+
|
|
221
|
+
if [ "$NON_INTERACTIVE" = true ]; then
|
|
222
|
+
print_info "Non-interactive mode — set your token later:"
|
|
223
|
+
echo " Start opencode, switch to the ForLoop Planner agent, and say 'set my API token'"
|
|
224
|
+
return
|
|
225
|
+
fi
|
|
226
|
+
|
|
227
|
+
read -p "Have you created a token? [y/N] " -r; echo
|
|
228
|
+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
229
|
+
print_info "Set it later: start opencode, switch to the ForLoop Planner agent, and say 'set my API token'"
|
|
230
|
+
return
|
|
231
|
+
fi
|
|
232
|
+
|
|
233
|
+
local TOKEN
|
|
234
|
+
read -p "Enter your token: " -s TOKEN; echo
|
|
235
|
+
if [ -z "$TOKEN" ]; then
|
|
236
|
+
print_info "No token entered, skipping"
|
|
237
|
+
return
|
|
238
|
+
fi
|
|
239
|
+
|
|
240
|
+
local token_dir="$HOME/.config/forloop"
|
|
241
|
+
mkdir -p "$token_dir"
|
|
242
|
+
jq -n --arg token "$TOKEN" --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")" '
|
|
243
|
+
{version: "1.0", note: "ForLoop API tokens — do not share", default: $token, lastUpdated: $ts}
|
|
244
|
+
' > "$token_dir/tokens.json"
|
|
245
|
+
chmod 600 "$token_dir/tokens.json"
|
|
246
|
+
print_success "Token saved to: $token_dir/tokens.json"
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
# ── Summary ──────────────────────────────────────────────────────────────────
|
|
250
|
+
|
|
251
|
+
show_summary() {
|
|
252
|
+
local entry
|
|
253
|
+
entry="$(get_plugin_entry)"
|
|
254
|
+
echo ""
|
|
255
|
+
echo -e "${GREEN}${BOLD}========================================${NC}"
|
|
256
|
+
echo -e "${GREEN}${BOLD} Installation Complete!${NC}"
|
|
257
|
+
echo -e "${GREEN}${BOLD}========================================${NC}"
|
|
258
|
+
echo ""
|
|
259
|
+
echo " Type: $INSTALL_TYPE"
|
|
260
|
+
echo " Source: $entry"
|
|
261
|
+
echo ""
|
|
262
|
+
echo " Next steps:"
|
|
263
|
+
echo " 1. Start opencode: opencode"
|
|
264
|
+
echo " 2. Press TAB to switch to the ForLoop Planner agent"
|
|
265
|
+
echo " 3. Say: \"List my sprints\" or \"Create a story for login\""
|
|
266
|
+
echo ""
|
|
267
|
+
echo " Docs: https://github.com/forloop-cc/forloop-opencode-plugin-planner"
|
|
268
|
+
echo ""
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
# ── Main ─────────────────────────────────────────────────────────────────────
|
|
272
|
+
|
|
273
|
+
# Parse CLI flags
|
|
274
|
+
while [[ $# -gt 0 ]]; do
|
|
275
|
+
case "$1" in
|
|
276
|
+
-g|--global) INSTALL_TYPE="global"; shift ;;
|
|
277
|
+
-l|--local) INSTALL_TYPE="local"; shift ;;
|
|
278
|
+
-n|--npm) USE_NPM=true; shift ;;
|
|
279
|
+
--skip-agents) SKIP_AGENTS=true; shift ;;
|
|
280
|
+
-h|--help) show_help; exit 0 ;;
|
|
281
|
+
*) print_error "Unknown option: $1"; show_help; exit 1 ;;
|
|
282
|
+
esac
|
|
283
|
+
done
|
|
284
|
+
|
|
285
|
+
# Detect non-interactive mode (stdin is a pipe, not terminal)
|
|
286
|
+
if [ ! -t 0 ]; then
|
|
287
|
+
NON_INTERACTIVE=true
|
|
288
|
+
if [ -z "$INSTALL_TYPE" ]; then
|
|
289
|
+
print_info "Running in non-interactive mode, defaulting to local install"
|
|
290
|
+
INSTALL_TYPE="local"
|
|
291
|
+
fi
|
|
292
|
+
fi
|
|
293
|
+
|
|
294
|
+
print_header
|
|
295
|
+
|
|
296
|
+
# Interactive: prompt for install type if not given
|
|
297
|
+
if [ -z "$INSTALL_TYPE" ] && [ "$NON_INTERACTIVE" != true ]; then
|
|
298
|
+
echo -e "${BOLD}Choose installation type:${NC}"
|
|
299
|
+
echo " 1) Global — available for all projects (~/.config/opencode/opencode.json)"
|
|
300
|
+
echo " 2) Local — only for this project (./opencode.json)"
|
|
301
|
+
echo " 3) Cancel"
|
|
302
|
+
read -p "Select [1-3]: " -r; echo
|
|
303
|
+
case "$REPLY" in
|
|
304
|
+
1) INSTALL_TYPE="global" ;;
|
|
305
|
+
2) INSTALL_TYPE="local" ;;
|
|
306
|
+
*) print_info "Installation cancelled"; exit 0 ;;
|
|
307
|
+
esac
|
|
308
|
+
fi
|
|
309
|
+
[ -z "$INSTALL_TYPE" ] && { print_error "Installation type required"; exit 1; }
|
|
310
|
+
|
|
311
|
+
check_all_deps
|
|
312
|
+
merge_plugin_into_config
|
|
313
|
+
if [ "$SKIP_AGENTS" != true ]; then
|
|
314
|
+
setup_agents_skills
|
|
315
|
+
fi
|
|
316
|
+
setup_token
|
|
317
|
+
show_summary
|
package/package.json
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/package.json",
|
|
3
|
+
"name": "@forloop-cc/forloop-opencode-plugin-planner",
|
|
4
|
+
"version": "2.2.1",
|
|
5
|
+
"description": "ForLoop integration plugin for opencode — Sprint, story, and agent tools for the ForLoop platform",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"opencode",
|
|
10
|
+
"plugin",
|
|
11
|
+
"forloop",
|
|
12
|
+
"agile",
|
|
13
|
+
"sprint",
|
|
14
|
+
"ai"
|
|
15
|
+
],
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/forloop-cc/forloop-opencode-plugin-planner"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://github.com/forloop-cc/forloop-opencode-plugin-planner#readme",
|
|
21
|
+
"bugs": "https://github.com/forloop-cc/forloop-opencode-plugin-planner/issues",
|
|
22
|
+
"main": "./plugins/forloop-plugin.ts",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"import": "./plugins/forloop-plugin.ts",
|
|
26
|
+
"types": "./plugins/forloop-plugin.ts"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"plugins/",
|
|
31
|
+
"scripts/migrate-tokens.js",
|
|
32
|
+
"scripts/use-prod.sh",
|
|
33
|
+
"docs/",
|
|
34
|
+
"install.sh",
|
|
35
|
+
"update.sh",
|
|
36
|
+
"tsconfig.json",
|
|
37
|
+
"README.md",
|
|
38
|
+
"LICENSE",
|
|
39
|
+
"CHANGELOG.md",
|
|
40
|
+
"CODE_OF_CONDUCT.md",
|
|
41
|
+
"CONTRIBUTING.md",
|
|
42
|
+
"SECURITY.md"
|
|
43
|
+
],
|
|
44
|
+
"scripts": {
|
|
45
|
+
"typecheck": "tsc --noEmit",
|
|
46
|
+
"lint": "eslint plugins/",
|
|
47
|
+
"lint:fix": "eslint plugins/ --fix",
|
|
48
|
+
"format": "prettier --write plugins/",
|
|
49
|
+
"format:check": "prettier --check plugins/",
|
|
50
|
+
"test": "vitest run",
|
|
51
|
+
"test:unit": "vitest run test/suites/unit/",
|
|
52
|
+
"test:integration": "vitest run test/suites/integration/",
|
|
53
|
+
"test:skills": "vitest run test/suites/skills/",
|
|
54
|
+
"test:agents": "vitest run test/suites/agents/",
|
|
55
|
+
"test:watch": "vitest",
|
|
56
|
+
"test:coverage": "vitest run --coverage",
|
|
57
|
+
"migrate-tokens": "node ./scripts/migrate-tokens.js",
|
|
58
|
+
"prepublishOnly": "npm run typecheck && npm run lint",
|
|
59
|
+
"preversion": "npm run lint",
|
|
60
|
+
"version": "git add -A package.json",
|
|
61
|
+
"postversion": "git push && git push --tags"
|
|
62
|
+
},
|
|
63
|
+
"publishConfig": {
|
|
64
|
+
"access": "public"
|
|
65
|
+
},
|
|
66
|
+
"engines": {
|
|
67
|
+
"node": ">=18.0.0"
|
|
68
|
+
},
|
|
69
|
+
"peerDependencies": {
|
|
70
|
+
"@opencode-ai/plugin": "^1.3.0"
|
|
71
|
+
},
|
|
72
|
+
"dependencies": {
|
|
73
|
+
"@opencode-ai/plugin": "^1.3.0"
|
|
74
|
+
},
|
|
75
|
+
"devDependencies": {
|
|
76
|
+
"@types/js-yaml": "^4.0.9",
|
|
77
|
+
"@types/node": "^20.19.37",
|
|
78
|
+
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
|
79
|
+
"@typescript-eslint/parser": "^7.0.0",
|
|
80
|
+
"@vitest/coverage-v8": "^4.1.2",
|
|
81
|
+
"eslint": "^8.57.0",
|
|
82
|
+
"js-yaml": "^4.1.1",
|
|
83
|
+
"prettier": "^3.2.5",
|
|
84
|
+
"typescript": "^5.0.0",
|
|
85
|
+
"vitest": "^4.1.2"
|
|
86
|
+
}
|
|
87
|
+
}
|