first commit

This commit is contained in:
2026-03-12 00:56:57 +08:00
commit d1ef33c25a
9 changed files with 1393 additions and 0 deletions

32
.gitignore vendored Normal file
View File

@@ -0,0 +1,32 @@
# ── GSD baseline (auto-generated) ──
.gsd/activity/
.gsd/runtime/
.gsd/auto.lock
.gsd/metrics.json
.gsd/STATE.md
.DS_Store
Thumbs.db
*.swp
*.swo
*~
.idea/
.vscode/
*.code-workspace
.env
.env.*
!.env.example
node_modules/
.next/
dist/
build/
__pycache__/
*.pyc
.venv/
venv/
target/
vendor/
*.log
coverage/
.cache/
tmp/

View File

@@ -0,0 +1,116 @@
# Architecture
**Analysis Date:** 2026-03-12
## Pattern Overview
**Overall:** Agent-based task automation framework built on OpenCode
**Key Characteristics:**
- Modular command/agent system with specialized agents for different phases
- Workflow-driven execution with named phases (discovery, research, plan, execute, verify)
- Direct file output pattern - agents write to `.planning/codebase/` directly
- Subagent spawning for parallel exploration tasks
## Layers
**Commands Layer:**
- Purpose: User-facing entry points for GSD operations
- Location: `.opencode/commands/gsd/`
- Contains: Markdown command definitions with YAML frontmatter
- Files: 33 command files (gsd-*.md)
- Used by: OpenCode CLI when user invokes `/gsd-*` commands
**Agents Layer:**
- Purpose: Specialized AI agents for focused tasks
- Location: `.opencode/agents/`
- Contains: Agent role definitions with tools and skills
- Files: 12 agent definitions (gsd-*.md)
- Used by: Commands that need parallel or complex task execution
**Workflows Layer:**
- Purpose: Execution logic connecting commands and agents
- Location: `.opencode/get-shit-done/workflows/`
- Contains: Step-by-step workflow definitions
- Files: 36 workflow files
- Depends on: Commands layer (referenced in command execution_context)
- Used by: Command execution context
**Supporting Layers:**
- Skills: `.opencode/skills/` - Specialized skills (e.g., model selection)
- Rules: `.opencode/rules/` - Behavior rules (e.g., work-hard rule)
- Configuration: `.opencode/package.json`, `bun.lock` - Dependencies and lockfile
## Data Flow
**Command Invocation Flow:**
1. User invokes `/gsd-*` command
2. Command definition loads execution_context (workflow)
3. Workflow orchestrates agent spawning and task execution
4. Agents write outputs directly to `.planning/` directories
5. Confirmation returned to orchestrator (not full content)
**Parallel Agent Pattern:**
- map-codebase spawns 4 parallel mapper agents (tech, arch, quality, concerns)
- Each agent explores focus area and writes specific documents
- Agents return confirmations only to minimize context load
## Key Abstractions
**Command Pattern:**
- Format: Markdown with YAML frontmatter
- Structure: name, description, argument-hint, permissions, objective, execution_context, context, when_to_use, process, success_criteria
- Location: `.opencode/commands/gsd/gsd-{name}.md`
**Agent Pattern:**
- Format: Markdown with YAML frontmatter
- Structure: name, description, mode, tools, color, skills
- Location: `.opencode/agents/gsd-{name}.md`
- Types: orchestrator agents (main), subagents (parallel workers)
**Workflow Pattern:**
- Format: Markdown with step-by-step instructions
- Location: `.opencode/get-shit-done/workflows/{name}.md`
- Called from: Command's `<execution_context>` directive
## Entry Points
**Primary Entry Point:**
- Location: `.opencode/commands/gsd/gsd-*.md` (33 commands)
- Triggers: OpenCode CLI `/gsd-*` invocation
- Responsibilities: Define command interface, load workflow, return success criteria
**Command Categories:**
- Project management: new-project, new-milestone, resume-work, pause-work
- Phase management: add-phase, remove-phase, insert-phase, list-phase-assumptions
- Execution: plan-phase, execute-phase, verify-phase, validate-phase
- Discovery: research-phase, map-codebase, discuss-phase, quick
- Verification: audit-milestone, complete-milestone, verify-work, health
- Debugging: debug, diagnose-issues, reapply-patches
- Utilities: add-todo, add-tests, set-profile, settings, help
## Error Handling
**Workflow Error Handling:**
- Phase failures trigger diagnosis workflows
- verify-work performs health checks on each phase
- audit-milestone catches incomplete work before completion
**Agent Error Patterns:**
- Subagent failures reported to orchestrator with error details
- Parallel agents - one failure doesn't cascade to others
## Cross-Cutting Concerns
**State Management:**
- Project state stored in `.planning/STATE.md`
- Milestone data in `.gsd/milestones/`
- Codebase docs in `.planning/codebase/`
**Permissions System:**
- Commands declare required permissions (read, bash, glob, grep, write, task)
- Agents declare tools they can use
---
*Architecture analysis: 2026-03-12*

View File

@@ -0,0 +1,186 @@
# Codebase Concerns
**Analysis Date:** 2026-03-12
## Project Status: Greenfield
**Critical Finding:** This is a greenfield project with no actual implementation code. The repository contains only:
- `THE_IDEA.md` - Requirements specification document
- `.opencode/` - OpenCode/GSD framework configuration
**Impact:** There are no code-level technical concerns to document because nothing has been built yet. This document outlines concerns for the future implementation.
---
## Implementation Concerns
### No Source Code Exists
**Issue:** No application code has been implemented
- Files: None (project has not been initialized with source code)
- Impact: Cannot assess code quality, patterns, or technical debt
- Fix approach: Initialize project with proper scaffolding before implementation begins
### Missing Project Initialization
**Issue:** No package.json, build configuration, or source directories at project root
- Files: `package.json`, `tsconfig.json`, `src/` missing
- Impact: No standard development workflow established
- Fix approach: Run project initialization to create proper project structure
---
## Hardware-Specific Concerns
### Low-Power Device Targeting
**Issue:** Target hardware is Raspberry Pi Zero 2W (limited resources)
- Device: Pi Zero 2 W with 512MB RAM, single-core ARMv8
- Concern: UI must be lightweight to run smoothly in Chromium Kiosk Mode
- Mitigation needed:
- Minimal JavaScript bundle size
- Efficient rendering (avoid heavy frameworks if possible)
- Consider static HTML/CSS over SPA for main interface
- Lazy-load any heavy components
### Dual Display Resolution Support
**Issue:** Must support two different display modes
- 7-inch touchscreen: 1024x600 resolution
- Full HD remote access: 1920x1080 resolution
- Concern: Responsive design complexity
- Mitigation needed:
- Clear responsive breakpoints
- Different layouts for touch vs desktop
- Performance testing on actual hardware
---
## Requirements Complexity
### Feature Scope (3 Milestones)
**Issue:** Large feature set across three milestones
- Milestone 1: Modern compact UI
- Milestone 2: CSV processing and workflow
- Milestone 3: Network stack
- Concern: Scope creep and milestone creep
- Priority: High
### Data Types and Processing
**Issue:** Multiple sensor data types require handling
- Rainfall (today, hourly, MAR, yearly)
- Battery voltage
- Solar voltage
- Water level sensors (4-20mA, 0-10vDC)
- GPS coordinates
- Mobile network status
- Concern: Data normalization and storage complexity
### Network Protocol Support
**Issue:** Multiple transfer protocols specified in requirements
- FTP, SCP, SFTP, WEBDAV
- TCP socket connections
- Concern: Implementation complexity and security
- Mitigation: Start with simplest protocol (HTTP), add others as needed
---
## Dependencies at Risk
### OpenCode Framework Dependency
**Issue:** Project configured to use OpenCode/GSD workflow
- Package: `@opencode-ai/plugin` v1.2.24
- Location: `.opencode/package.json`
- Risk: Vendor lock-in to specific workflow tool
- Mitigation: Document standard development practices that work independently
### Zod in node_modules
**Issue:** Zod library present in `.opencode/node_modules/`
- Purpose: Likely used for configuration validation
- Concern: Not yet integrated into project (in .)
- Recommendation: If validationopencode only needed, use zod; otherwise remove dependency
---
## Missing Infrastructure
### No Testing Framework
**Issue:** No test files or configuration detected
- No `jest.config.*`, `vitest.config.*`, or similar
- No `*.test.*` or `*.spec.*` files
- Impact: No test coverage for future implementation
- Priority: High - Testing should be established before implementation
### No Linting/Formatting
**Issue:** No ESLint, Prettier, or biome configuration
- Impact: Inconsistent code style as team grows
- Priority: Medium
### No CI/CD Configuration
**Issue:** No GitHub Actions, GitLab CI, or similar
- Impact: No automated testing or deployment
- Priority: Low (can be added later)
---
## Security Considerations (Future)
### Network Credentials Storage
**Issue:** Requirements mention FTP/SCP credentials
- Files referenced: `THE_IDEA.md` lines 175-184
- Concern: Plain-text credentials in configuration
- Future mitigation:
- Use environment variables, not config files
- Consider OAuth/API keys over username/password
- Encrypt any stored credentials
### GPRS/Mobile Network
**Issue:** Mobile settings stored in system
- Location: `THE_IDEA.md` section 1.7
- Concern: Phone numbers and device IDs stored
- Future mitigation: Encrypt sensitive station data
---
## Performance Targets
### Startup Time
**Target:** Fast enough for Pi Zero 2W Chromium Kiosk
- Concern: Cold start must be under 3 seconds
- Mitigation: Minimize JavaScript, use progressive loading
### Memory Usage
**Target:** Stay within 256MB RAM for UI
- Concern: Chromium + web app + system services
- Mitigation: Avoid large in-memory data structures
---
## Summary of Priorities
| Concern | Priority | Status |
|---------|----------|--------|
| No source code exists | Critical | Not started |
| No testing framework | High | Not started |
| No project initialization | High | Not started |
| Hardware performance | High | Future |
| Requirements scope | Medium | Planned |
| No CI/CD | Low | Not started |
| Security hardening | Medium | Future |
---
*Concerns audit: 2026-03-12*

View File

@@ -0,0 +1,239 @@
# Coding Conventions
**Analysis Date:** 2026-03-12
## Language
**Primary:** JavaScript (Node.js)
- All source files use CommonJS (`.cjs` extension)
- ESM imports used in test files with `.test.cjs` extension
## File Naming
**Pattern:** kebab-case
- Commands: `allow-read-config.cjs`, `get-profile.cjs`, `set-profile.cjs`
- Libraries: `oc-core.cjs`, `oc-config.cjs`, `oc-models.cjs`
- Tests: `get-profile.test.cjs`, `allow-read-config.test.cjs`
**Directories:**
- Commands: `bin/gsd-oc-commands/`
- Libraries: `bin/gsd-oc-lib/` or `bin/lib/`
- Tests: `bin/test/`
## Code Style
### Formatting
**No explicit formatter configured.** Code uses:
- 2-space indentation
- Consistent brace placement
- Max line length ~100 characters
**Example from `bin/gsd-oc-commands/get-profile.cjs`:**
```javascript
function getProfile(cwd, args) {
const verbose = args.includes('--verbose');
const raw = args.includes('--raw');
const log = verbose ? (...args) => console.error('[get-profile]', ...args) : () => {};
// ...
}
```
### Linting
**No ESLint or Prettier configuration detected.**
## Import Organization
**Order in source files:**
1. Node.js built-ins (`fs`, `path`, `os`)
2. Local modules relative paths
**Example from `bin/gsd-oc-commands/allow-read-config.cjs`:**
```javascript
const fs = require('fs');
const path = require('path');
const os = require('os');
const { output, error, createBackup } = require('../gsd-oc-lib/oc-core.cjs');
```
## Function Design
### Naming
- Commands: lowercase with hyphens (e.g., `getProfile`, `allowReadConfig`)
- Helper functions: camelCase
- Error code constants: UPPER_SNAKE_CASE
### Documentation
**Every file includes a JSDoc-style header:**
```javascript
/**
* get-profile.cjs — Retrieve profile definitions from oc_config.json
*
* Command module that exports getProfile(cwd, args) function with two operation modes:
* 1. No parameters: Returns current profile definition
* 2. Profile name parameter: Returns specified profile definition
*
* Output format: JSON envelope {success: true, data: {...}}
* Flags: --raw (output raw JSON without envelope), --verbose (output diagnostics to stderr)
*
* Usage: node get-profile.cjs [profile-name] [--raw] [--verbose]
*/
```
**Function JSDoc:**
```javascript
/**
* Main command function
*
* @param {string} cwd - Current working directory
* @param {string[]} args - Command line arguments
*/
function getProfile(cwd, args) {
```
## Error Handling
### Error Codes
**Pattern:** Constant object with error codes, used with custom error function
From `bin/gsd-oc-lib/oc-profile-config.cjs`:
```javascript
const ERROR_CODES = {
CONFIG_NOT_FOUND: 'CONFIG_NOT_FOUND',
INVALID_JSON: 'INVALID_JSON',
PROFILE_NOT_FOUND: 'PROFILE_NOT_FOUND',
INVALID_MODELS: 'INVALID_MODELS',
INCOMPLETE_PROFILE: 'INCOMPLETE_PROFILE',
WRITE_FAILED: 'WRITE_FAILED',
APPLY_FAILED: 'APPLY_FAILED',
ROLLBACK_FAILED: 'ROLLBACK_FAILED'
};
```
### Output Pattern
**Success output:** JSON envelope with `success: true` and `data`
```javascript
output({ success: true, data: result });
```
**Error output:** Uses centralized `error()` function from `oc-core.cjs`
```javascript
error('current_oc_profile not set in oc_config.json', 'MISSING_CURRENT_PROFILE');
```
From `bin/gsd-oc-lib/oc-core.cjs`:
```javascript
function error(message, code = 'UNKNOWN_ERROR') {
const errorEnvelope = {
success: false,
error: {
code,
message
}
};
console.error(JSON.stringify(errorEnvelope, null, 2));
process.exit(1);
}
```
## Return Patterns
### Result Objects
**Pattern:** Return object with `success: boolean` and either `data` or `error`
From `bin/gsd-oc-lib/oc-profile-config.cjs`:
```javascript
function loadOcProfileConfig(cwd) {
try {
const configPath = path.join(cwd, '.planning', 'oc_config.json');
if (!fs.existsSync(configPath)) {
return {
success: false,
error: {
code: ERROR_CODES.CONFIG_NOT_FOUND,
message: `.planning/oc_config.json not found at ${configPath}`
}
};
}
return { success: true, config, configPath };
} catch (err) {
// ...
}
}
```
## Module Design
### Exports
**Pattern:** Single function export via `module.exports`
```javascript
module.exports = getProfile;
```
### Command Module Structure
1. JSDoc header with description
2. Require statements
3. Error code constants
4. Helper functions
5. Main command function
6. `module.exports`
## CLI Patterns
### Flag Handling
**Pattern:** Simple array filtering
```javascript
const verbose = args.includes('--verbose');
const raw = args.includes('--raw');
const profileArgs = args.filter(arg => !arg.startsWith('--'));
```
### Output Functions
From `bin/gsd-oc-lib/oc-core.cjs`:
```javascript
function output(result, raw = false, rawValue = null) {
let outputStr;
if (raw && rawValue !== null) {
outputStr = rawValue;
} else {
outputStr = JSON.stringify(result, null, 2);
}
// Large payload handling (>50KB)
if (outputStr.length > 50 * 1024) {
const tempFile = path.join(require('os').tmpdir(), `gsd-oc-${Date.now()}.json`);
fs.writeFileSync(tempFile, outputStr, 'utf8');
console.log(`@file:${tempFile}`);
} else {
console.log(outputStr);
}
}
```
## Logging
### Verbose Logging Pattern
**Conditional logging based on flag:**
```javascript
const log = verbose ? (...args) => console.error('[get-profile]', ...args) : () => {};
log('Loading oc_config.json');
log(`Config loaded from ${configPath}`);
```
## Testing Conventions
Tests co-located in `bin/test/` directory with `.test.cjs` suffix.
---
*Convention analysis: 2026-03-12*

View File

@@ -0,0 +1,190 @@
# External Integrations
**Analysis Date:** 2026-03-12
## Project Status
This is a **greenfield project** - no implementation code exists yet. The following analysis is based on the requirements defined in `THE_IDEA.md`.
---
## Hardware Interfaces
### Sensors
**Rainfall Sensors:**
- Rainfall-1 ID (RF) - Primary rainfall sensor (e.g., `123456RF`)
- Rainfall-2 ID - Secondary rainfall sensor
- Tip bucket counting for rainfall accumulation
**Water Level Sensors:**
- 4-20mA type sensors (Channels 1-2)
- 0-10vDC type sensors (Channels 3-4)
- SDI-12 interface for additional sensors
**Environmental Sensors:**
- Solar voltage monitoring
- Battery voltage monitoring
- Soil moisture sensors (SDI-12)
- Evapotranspiration sensors
### GPS Module
- USB GPS module for location data
- Latitude/longitude retrieval
- Manual coordinate setting as fallback
---
## Data Storage
### Local Storage
**CSV Files:**
- Data logging to local filesystem
- File naming: `SP8020_FTP.txt`, `SP8021_FTP.txt`, etc.
- Flash memory management for stored files
- File operations: Navigate, View, Delete, Save
**Data Types Logged:**
- Rainfall (today, hourly, monthly accumulated, yearly)
- Water levels
- Battery voltage
- Solar voltage
- Sensor readings (ADC channels)
---
## Network & External Services
### Data Server (myvscada)
**Server Details:**
- Remote server for receiving CSV data
- Location: Configurable IP address
- Protocol: FTP, SCP, SFTP, or WEBDAV
**Transfer Flow:**
```
RTU → CSV file → myvscada server → received folder → processed/error folder
```
### Mobile Network (GPRS)
**GPRS Module:**
- Mobile network connectivity for remote transmission
- RTU Mobile number configuration
- Referenced in "Mobile Setting" submenu (THE_IDEA.md section 1.7)
### Protocols Supported
| Protocol | Purpose | Reference |
|----------|---------|-----------|
| FTP | CSV file transfer | Primary protocol mentioned |
| SCP | Secure copy | Section 1.6 |
| SFTP | Secure FTP | Section 1.6 |
| WebDAV | Web-based file access | Section 1.6 |
| TCP Socket | Real-time data requests | Section 1.6 |
---
## Authentication & Identity
**Station Configuration:**
- Station ID (e.g., `D007`)
- Device version number (e.g., `v4.0.4`)
- Login status for remote access
**Network Credentials:**
- FTP/SCP username and password
- Referenced in THE_IDEA.md section 1.6 (Protocol Setting)
- **Note:** Credentials should be stored securely (env vars, not plain config)
---
## Alert Systems
### SMS/Call Alerts
**Contact Types:**
- Master phones (2 numbers)
- SubMaster phones (2 numbers)
- Engineer phones (up to 10 numbers)
- RTU Mobile number
**Alert Triggers:**
- Danger rainfall threshold (configurable mm per hour)
- Warning rainfall threshold
- Water level thresholds (Danger, Warning, Alert, Normal)
---
## Display Interfaces
### Local Touchscreen
- **Resolution:** 1024x600
- **Connection:** Direct video output (HDMI/CSI)
- **Browser:** Chromium Kiosk Mode
- **URL:** `http://pihostname:8080`
### Remote Web Access
- **Resolution:** Full HD (1920x1080)
- **Authentication:** Login required
- **URL:** `http://pihostname:9090/`
---
## Communication Status
**Monitoring Data:**
- Communication status display (e.g., `0ASU/-113dBm(0%)`)
- Signal strength (dBm)
- Connection percentage
---
## Environment Configuration
### Required Configuration Items
**Network:**
- Local IP Address
- Subnet Mask
- Gateway
- DNS Server
- MAC Address
- Transfer Protocol (FTP/SCP/SFTP/WEBDAV)
**Server:**
- Server IP Address
- TCP Port
- File Directory (e.g., `/myvscada/stationA`)
**Sensors:**
- ADC channel types (4-20mA, 0-10vDC)
- Sensor datum offsets
- Sensor ranges and units
---
## Data Flow Summary
```
Sensors (ADC, RF, WL)
Python Backend (data collection)
CSV File Generation
Transfer Protocol (FTP/SCP/SFTP/WebDAV)
myvscada Server
Processed/Error folder handling
```
---
*Integration audit: 2026-03-12*

137
.planning/codebase/STACK.md Normal file
View File

@@ -0,0 +1,137 @@
# Technology Stack
**Analysis Date:** 2026-03-12
## Project Status
This is a **greenfield project** - no implementation code exists yet. The repository currently contains only:
- `THE_IDEA.md` - Requirements specification document
- `.opencode/` - OpenCode/GSD framework configuration
The following stack analysis is based on the requirements defined in `THE_IDEA.md`.
---
## Languages
**Primary:**
- **HTML/CSS/JavaScript** - Web-based UI for the 7-inch touchscreen and remote full HD interface
- Expected to run in Chromium Kiosk Mode on Raspberry Pi
- Must support dual resolution: 1024x600 (touchscreen) and 1920x1080 (remote)
**Secondary:**
- **Python** (likely) - Backend for sensor data collection, CSV processing, and network operations
- Raspberry Pi standard runtime
- Used for serial communication with sensors (ADC, rainfall sensors)
- CSV file generation and management
---
## Runtime
**Environment:**
- **Raspberry Pi OS** - Primary runtime on Pi Zero 2 W and Pi 3B
- Pi Zero 2 W: ARMv8 single-core, 512MB RAM
- Pi 3B: ARMv7 quad-core, 1GB RAM
**Browser:**
- **Chromium** - Kiosk mode for touchscreen interface
- Target URL: `http://pihostname:8080` (touchscreen)
- Target URL: `http://pihostname:9090/` (remote full HD)
**Package Manager:**
- Not yet established (pending project initialization)
---
## Frameworks
**Core:**
- **Lightweight web framework** (TBD) - For serving the UI
- Options: Flask, FastAPI (Python), or simple HTTP server
- Must be performant on low-power Pi Zero 2 W
- **Frontend** - Plain HTML/CSS or lightweight framework
- Recommendation: Static HTML/CSS for main interface (performance)
- Avoid heavy SPA frameworks to minimize memory footprint
**Sensor Interfaces:**
- **Serial communication** - For ADC, rainfall sensors, GPS
- **SDI-12** - For soil moisture and evapotranspiration sensors (referenced in requirements)
**Data Handling:**
- **CSV processing** - For data logging and transfer (per flowchart in THE_IDEA.md)
**Build/Dev:**
- Not yet established (pending project initialization)
---
## Key Dependencies
**Hardware Interfaces:**
- Serial port communication (Python pyserial or similar)
- ADC reading libraries
- GPS module support (USB)
**Network:**
- FTP client (for data transfer to myvscada server)
- SCP/SFTP client
- WebDAV client
- TCP socket libraries
**Data Processing:**
- CSV generation and parsing libraries
- Data validation utilities
---
## Configuration
**Network Settings:**
- Local IP configuration (static IP)
- Subnet mask, gateway, DNS
- MAC address
- Transfer protocol selection (FTP/SCP/SFTP/WEBDAV)
**Sensor Configuration:**
- ADC channels (4-20mA, 0-10vDC types)
- Rainfall sensor settings
- Water level thresholds
- Evapotranspiration settings
**Server Settings:**
- Server IP and TCP port
- Tide data hours
- GPS coordinates (manual or USB GPS)
**Mobile Settings:**
- Phone numbers for alerts (Master, SubMaster, Engineer contacts)
---
## Platform Requirements
**Development:**
- Standard web development tools (editor, browser)
- Python development environment
- Git for version control
**Production:**
- Raspberry Pi Zero 2 W or 3B
- 7-inch capacitive touchscreen (1024x600)
- Chromium browser (Kiosk mode)
- Network connectivity (Ethernet or mobile/GPRS)
---
## Performance Constraints
| Resource | Target | Concern |
|----------|--------|---------|
| RAM | <256MB for UI | Pi Zero 2 W has only 512MB total |
| Startup time | <3 seconds | Cold start in Chromium Kiosk |
| Bundle size | Minimal | Optimize for low-power device |
---
*Stack analysis: 2026-03-12*

View File

@@ -0,0 +1,148 @@
# Codebase Structure
**Analysis Date:** 2026-03-12
## Directory Layout
```
/root/tckuiyo/
├── THE_IDEA.md # Project concept documentation
├── .gitignore # Git ignore rules
├── .bg-shell/ # Background shell config (manifest.json)
├── .gsd/ # GSD project data
│ └── milestones/ # Milestone definitions (empty)
├── .opencode/ # GSD Framework (main project code)
│ ├── package.json # Dependencies (OpenCode plugin)
│ ├── bun.lock # Dependency lockfile
│ ├── opencode.db # OpenCode database
│ ├── commands/ # User-facing commands
│ ├── agents/ # AI agent definitions
│ ├── get-shit-done/ # Workflows
│ │ └── workflows/ # Execution logic
│ ├── skills/ # Specialized skills
│ ├── rules/ # Behavior rules
│ ├── node_modules/ # Dependencies
│ └── .gitignore # OpenCode-specific ignores
├── .planning/ # Project planning output
│ └── codebase/ # Codebase analysis docs (where mappers write)
└── (empty directories for future use)
```
## Directory Purposes
**`.opencode/`:**
- Purpose: Core GSD framework configuration
- Contains: Commands, agents, workflows, skills, rules
- Key files: All 33 command files, 12 agent files, 36 workflow files
**`.opencode/commands/gsd/`:**
- Purpose: User-invokable GSD commands
- Contains: Markdown command definitions with YAML frontmatter
- Key files: `gsd-new-project.md`, `gsd-map-codebase.md`, `gsd-plan-phase.md`, `gsd-execute-phase.md`
**`.opencode/agents/`:**
- Purpose: AI agent role definitions
- Contains: Agent configurations with tools and skills
- Key files: `gsd-codebase-mapper.md`, `gsd-planner.md`, `gsd-executor.md`, `gsd-verifier.md`
**`.opencode/get-shit-done/workflows/`:**
- Purpose: Execution logic for commands
- Contains: Step-by-step workflow instructions
- Key files: `map-codebase.md`, `new-project.md`, `plan-phase.md`, `execute-phase.md`
**`.opencode/skills/`:**
- Purpose: Specialized capability modules
- Contains: Skill definitions with scripts
- Key files: `gsd-oc-select-model/` (model selection skill)
**`.opencode/rules/`:**
- Purpose: Global behavior rules
- Contains: Rule definitions for agent behavior
- Key files: `gsd-oc-work-hard.md`
**`.planning/codebase/`:**
- Purpose: Output location for codebase mapper agents
- Contains: Analysis documents written by mapper agents
- Target files: STACK.md, INTEGRATIONS.md, ARCHITECTURE.md, STRUCTURE.md, CONVENTIONS.md, TESTING.md, CONCERNS.md
**`.gsd/milestones/`:**
- Purpose: Milestone definitions for projects
- Contains: Milestone JSON files (currently empty)
- Used by: new-milestone, complete-milestone commands
## Key File Locations
**Entry Points:**
- `.opencode/commands/gsd/gsd-*.md`: Command definitions invoked via `/gsd-*`
**Configuration:**
- `.opencode/package.json`: Dependencies - `@opencode-ai/plugin: 1.2.24`
- `.opencode/bun.lock`: Dependency lockfile
- `.gitignore`: Excludes node_modules, .opencode/, .gsd/, .planning/, *.swp
**Core Logic:**
- All logic in `.opencode/` - this IS the application (OpenCode configuration)
**Testing:**
- No separate test directory - OpenCode handles testing via verify-work workflow
## Naming Conventions
**Files:**
- Commands: `gsd-{command-name}.md` (kebab-case)
- Agents: `gsd-{agent-name}.md` (kebab-case)
- Workflows: `{workflow-name}.md` (kebab-case)
- Skills: `{skill-name}/` directory with SKILL.md inside
**Directories:**
- `.opencode/commands/gsd/`: GSD commands group
- `.opencode/agents/`: Agent definitions
- `.opencode/get-shit-done/workflows/`: Workflow definitions
- `.opencode/skills/`: Skill packages
- `.opencode/node_modules/`: npm dependencies
- `.planning/codebase/`: Codebase analysis outputs
## Where to Add New Code
**New Command:**
- Implementation: `.opencode/commands/gsd/gsd-{name}.md`
- Workflow: Add corresponding `.opencode/get-shit-done/workflows/{name}.md`
**New Agent:**
- Implementation: `.opencode/agents/gsd-{name}.md`
**New Workflow:**
- Implementation: `.opencode/get-shit-done/workflows/{name}.md`
- Referenced by: Command's `<execution_context>` tag
**New Skill:**
- Implementation: `.opencode/skills/{skill-name}/SKILL.md`
**Codebase Analysis Output:**
- Location: `.planning/codebase/` (written by gsd-codebase-mapper agents)
## Special Directories
**`.opencode/`:**
- Purpose: OpenCode project root - contains all project code
- Generated: No - this IS the codebase
- Committed: Yes - core project files
**`.opencode/node_modules/`:**
- Purpose: Dependencies for OpenCode plugin
- Generated: Yes (via bun install)
- Committed: No (in .gitignore)
**`.planning/`:**
- Purpose: Planning output and project state
- Generated: Yes (by GSD commands)
- Committed: Yes (project state is versioned)
**`.gsd/`:**
- Purpose: Project milestone and tracking data
- Generated: Yes (by GSD commands)
- Committed: Yes (project progress is versioned)
---
*Structure analysis: 2026-03-12*

View File

@@ -0,0 +1,345 @@
# Testing Patterns
**Analysis Date:** 2026-03-12
## Test Framework
**Mixed approach detected:**
### Primary: Node.js built-in `node:test`
- Used in `bin/gsd-tools.test.cjs`
- Version: Node.js built-in (no package needed)
- Config: None detected
### Secondary: Vitest
- Used in `bin/test/*.test.cjs` files
- Version: `^3.2.4` (from package.json)
- Config: None detected (uses defaults)
**Run Commands:**
```bash
npm test # Run all tests (vitest run)
npm run test:watch # Watch mode (vitest)
```
## Test File Organization
**Location:** `bin/test/`
**Naming:** `{command-name}.test.cjs`
**Example files:**
- `bin/test/get-profile.test.cjs`
- `bin/test/set-profile.test.cjs`
- `bin/test/allow-read-config.test.cjs`
- `bin/test/oc-profile-config.test.cjs`
- `bin/test/pivot-profile.test.cjs`
## Test Structure
### Vitest Style (Recommended)
From `bin/test/get-profile.test.cjs`:
```javascript
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import fs from 'fs';
import path from 'path';
import os from 'os';
describe('get-profile.cjs', () => {
let testDir;
let planningDir;
let configPath;
let capturedLog;
let capturedError;
let exitCode;
beforeEach(() => {
// Create isolated test directory
testDir = fs.mkdtempSync(path.join(os.tmpdir(), 'get-profile-test-'));
planningDir = path.join(testDir, '.planning');
configPath = path.join(planningDir, 'oc_config.json');
fs.mkdirSync(planningDir, { recursive: true });
// Reset captured output
capturedLog = null;
capturedError = null;
exitCode = null;
// Mock console.log to capture all output
console.log = (msg) => {
allLogs.push(msg);
capturedLog = msg;
};
console.error = (msg) => {
allErrors.push(msg);
capturedError = msg;
};
process.exit = (code) => {
exitCode = code;
throw new Error(`process.exit(${code})`);
};
});
afterEach(() => {
// Restore original functions
console.log = originalLog;
console.error = originalError;
process.exit = originalExit;
// Cleanup test directory
try {
fs.rmSync(testDir, { recursive: true, force: true });
} catch (err) {
// Ignore cleanup errors
}
});
it('returns current profile when current_oc_profile is set', () => {
fs.writeFileSync(configPath, JSON.stringify(VALID_CONFIG_WITH_CURRENT, null, 2));
const getProfile = importGetProfile();
try {
getProfile(testDir, []);
} catch (err) {
// Expected to throw due to process.exit mock
}
expect(exitCode).toBe(0);
const output = JSON.parse(capturedLog);
expect(output.success).toBe(true);
});
});
```
### Node:test Style
From `bin/gsd-tools.test.cjs`:
```javascript
const { test, describe, beforeEach, afterEach } = require('node:test');
const assert = require('node:assert');
const fs = require('fs');
const path = require('path');
describe('history-digest command', () => {
let tmpDir;
beforeEach(() => {
tmpDir = createTempProject();
});
afterEach(() => {
cleanup(tmpDir);
});
test('empty phases directory returns valid schema', () => {
const result = runGsdTools('history-digest', tmpDir);
assert.ok(result.success, `Command failed: ${result.error}`);
const digest = JSON.parse(result.output);
assert.deepStrictEqual(digest.phases, {}, 'phases should be empty object');
});
});
```
### Manual Test Runner Style
From `bin/test/allow-read-config.test.cjs`:
```javascript
function testCreatePermission() {
console.log('Test: Create new opencode.json with permission...');
const testDir = createTestDir();
try {
const result = runCLI(testDir, []);
if (!result.success) {
throw new Error(`Expected success, got: ${JSON.stringify(result)}`);
}
// Verify opencode.json was created
const opencodePath = path.join(testDir, 'opencode.json');
if (!fs.existsSync(opencodePath)) {
throw new Error('opencode.json was not created');
}
console.log('✓ PASS: Create permission\n');
return true;
} catch (err) {
console.error('✗ FAIL:', err.message, '\n');
return false;
} finally {
cleanupTestDir(testDir);
}
}
function runTests() {
console.log('Running allow-read-config tests...\n');
const results = [
testCreatePermission(),
testIdempotency(),
testDryRun(),
];
const passed = results.filter(r => r).length;
console.log(`Results: ${passed}/${total} tests passed`);
if (passed === total) {
process.exit(0);
} else {
process.exit(1);
}
}
runTests();
```
## Mocking Patterns
### Console/Process Mocking
**Vitest approach:**
```javascript
const originalLog = console.log;
const originalError = console.error;
const originalExit = process.exit;
beforeEach(() => {
console.log = (msg) => {
allLogs.push(msg);
capturedLog = msg;
};
console.error = (msg) => {
allErrors.push(msg);
capturedError = msg;
};
process.exit = (code) => {
exitCode = code;
throw new Error(`process.exit(${code})`);
};
});
afterEach(() => {
console.log = originalLog;
console.error = originalError;
process.exit = originalExit;
});
```
### Require Cache Clearing
```javascript
const importGetProfile = () => {
const modulePath = '../gsd-oc-commands/get-profile.cjs';
delete require.cache[require.resolve(modulePath)];
return require(modulePath);
};
```
## Test Fixtures
**Location:** `bin/test/fixtures/`
**Pattern:** In-file constants
```javascript
const VALID_CONFIG_WITH_CURRENT = {
current_oc_profile: 'smart',
profiles: {
presets: {
simple: {
planning: 'bailian-coding-plan/qwen3.5-plus',
execution: 'bailian-coding-plan/qwen3.5-plus',
verification: 'bailian-coding-plan/qwen3.5-plus'
},
smart: { /* ... */ }
}
}
};
```
## Test Helpers
### CLI Execution
```javascript
function runCLI(testDir, args) {
const cmd = `node ${TOOLS_PATH} allow-read-config ${args.join(' ')}`;
const output = execSync(cmd, { cwd: testDir, encoding: 'utf8' });
return JSON.parse(output);
}
```
### Temp Directory Creation
```javascript
function createTestDir() {
const testDir = path.join(os.tmpdir(), `gsd-oc-test-${Date.now()}`);
fs.mkdirSync(testDir, { recursive: true });
return testDir;
}
function cleanupTestDir(testDir) {
if (fs.existsSync(testDir)) {
fs.rmSync(testDir, { recursive: true, force: true });
}
}
```
## Assertion Patterns
### Vitest
```javascript
expect(exitCode).toBe(0);
expect(output.success).toBe(true);
expect(output.data).toHaveProperty('smart');
expect(output.data.smart).toEqual(VALID_CONFIG_WITH_CURRENT.profiles.presets.smart);
```
### Node.js assert
```javascript
assert.ok(result.success, `Command failed: ${result.error}`);
assert.deepStrictEqual(digest.phases, {}, 'phases should be empty object');
```
## Coverage
**No coverage configuration detected.** No enforcement of coverage thresholds.
## Test Types
### Unit Tests
- Individual function testing
- Use mocking for dependencies
- Test isolated behavior
### Integration/CLI Tests
- Execute CLI commands via `execSync`
- Test with real temporary directories
- Verify file creation/state changes
### Patterns
- Test both success and error paths
- Test flag combinations (--verbose, --dry-run)
- Test idempotency (running same command twice)
## Common Issues
### Inconsistent Test Frameworks
- Some tests use Vitest, others use Node.js built-in `node:test`
- Some tests use manual test runner (no framework)
- **Recommendation:** Standardize on one framework
### Missing Test Config
- No `vitest.config.js` found
- No `jest.config.js` found
- **Recommendation:** Add configuration file
---
*Testing analysis: 2026-03-12*

0
README.md Normal file
View File