Skip to content

Commit 4527186

Browse files
authored
feat: Add allow-read-config command for GSD external directory permission (#84)
* feat(14-01): create core infrastructure libraries (oc-core.cjs, oc-models.cjs) - oc-core.cjs: output/json envelope, error handling, safeReadFile, createBackup - oc-models.cjs: getModelCatalog from opencode models, validateModelIds against catalog - Follows gsd-tools.cjs architecture pattern with CommonJS modules - Synchronous file ops appropriate for CLI utilities * feat(14-01): create check-opencode-json command - Validates model IDs in opencode.json against opencode models catalog - Outputs JSON envelope format with validation results - Supports --verbose flag for detailed logging - Exit code 0 for valid, 1 for invalid/error - Error codes: CONFIG_NOT_FOUND, INVALID_JSON, FETCH_FAILED, INVALID_MODEL_ID * feat(14-01): create check-config-json command - Validates profile configuration in .planning/config.json - Checks profile_type and profile names against whitelist (simple|smart|genius) - Outputs JSON envelope format with validation results - Exit code 0 for valid, 1 for invalid/error - Error codes: CONFIG_NOT_FOUND, INVALID_JSON, INVALID_PROFILE * feat(14-01): create gsd-oc-tools.cjs main entry point - Main CLI router with command routing via switch statement - Routes check-opencode-json, check-config-json, and help commands - Parses --verbose and --raw flags from command line - Shows help message with available commands and examples - Error handling with standardized JSON envelope format - Follows gsd-tools.cjs architecture pattern * feat(14-02): create oc-config.cjs library module - Add loadProfileConfig function to load .planning/config.json - Add applyProfileToOpencode function to update agent model assignments - Define VALID_PROFILES constant (simple|smart|genius) - Define PROFILE_AGENT_MAPPING for planning/execution/verification agents - Profile to agent mapping follows context specifications * feat(14-02): create update-opencode-json command - Add command to update opencode.json agent models from profile config - Support --dry-run flag to preview changes without modifying - Support --verbose flag for detailed output - Create timestamped backup before modifications using createBackup() - Validate profile_type against whitelist (simple|smart|genius) - Output JSON envelope with backup path and updated agents list - Proper error codes: CONFIG_NOT_FOUND, INVALID_PROFILE, BACKUP_FAILED, UPDATE_FAILED * feat(14-02): register update-opencode-json command - Add update-opencode-json case to command switch - Update help text with new command description - Add --dry-run option to help examples - Keep existing check-opencode-json and check-config-json commands * fix(14-02): support profiles.models profile structure - Update oc-config.cjs to handle profiles.models.{planning|execution|verification} - Update update-opencode-json.cjs dry-run mode with same fix - Fallback to profiles.{type} structure for backward compatibility - Tested: update-opencode-json creates backup and updates all 11 agents - Tested: INVALID_PROFILE error with exit code 1 * docs(14-02): complete update-opencode-json plan - Create 14-02-SUMMARY.md with execution details - Update STATE.md with plan completion and session info - Update ROADMAP.md: Phase 14 now 2/2 plans complete - All 3 tasks + 1 auto-fix committed - Verified: update-opencode-json creates backups, updates 11 agents * feat(oc-tools): create gsd-oc-commands and gsd-oc-lib directories - Rename bin/commands → bin/gsd-oc-commands (3 command files) - Create bin/gsd-oc-lib with oc-* libraries (oc-core, oc-config, oc-models) - Update all require paths in gsd-oc-tools.cjs and command files - Extend check-config-json to validate model IDs against opencode models catalog - Add --verbose flag to check-config-json for detailed validation output * feat(quick-4-01): enhance applyProfileToOpencode to return model IDs - Change updatedAgents array to contain { agent, model } objects - Maintains backward compatibility (updated field still exists) - Provides model ID details for each updated agent * feat(quick-4-01): add model IDs to command output - Dry-run mode: include modelId in changes array - Actual mode: add details field with { agent, model } objects - Maintain backward compatibility: updated array contains agent names * docs(quick-4-01): complete extend-return-of-update-opencode-json plan - SUMMARY.md created with full execution details - STATE.md updated with Quick Task 4 completion - Added task 4 to Quick Tasks Completed table - Updated session timestamp and focus * feat(quick-5-01): create gsd-oc-check-profile validation workflow - Workflow checks both opencode.json and .planning/config.json - Uses gsd-oc-tools.cjs check-opencode-json and check-config-json commands - Fast success path when both checks pass - Detailed error display with /gsd-set-profile recommendation when issues found - Supports --verbose flag for debugging * docs(quick-5): complete profile validation workflow plan - Created 5-SUMMARY.md with workflow documentation - Updated STATE.md with quick task 5 completion - Workflow validates opencode.json and .planning/config.json - Provides /gsd-set-profile remediation guidance * config: switch to simple profile with qwen3.5-plus for all stages * refactor(workflows): rename gsd-oc-check-profile to oc-check-profile and update oc-set-profile * Extend gsd-oc-tools with profile management commands Add 4 new commands to optimize oc-set-profile workflow: - validate-models: Validate model IDs against opencode catalog - analyze-reuse: Analyze model reuse opportunities for profile switching - migrate-config: Migrate legacy config to current profile format - set-profile: Switch profile with interactive model selection Update oc-set-profile.md workflow to use new tools instead of manual bash operations, providing: - Automatic backups before file modifications - Consistent JSON envelope output format - Dry-run support for previewing changes - Centralized error handling * Fix gsd-oc-tools.cjs paths in workflows Change relative paths (gsd-opencode/...) to absolute paths (~/.config/opencode/...) in: - oc-set-profile.md - oc-check-profile.md This ensures workflows work correctly in user environments where gsd-opencode/ directory structure may not exist. * Refactor check-config-json and remove unused commands Per up.md requirements: check-config-json updates: - Validate current_oc_profile field (required, must be simple|smart|genius) - Validate profiles.profile_type (must be simple|smart|genius) - Validate profiles.models has required stages for current profile - Validate all model IDs against opencode catalog - Fail if current_oc_profile missing or invalid Removed commands: - analyze-reuse.cjs (deleted) - migrate-config.cjs (deleted) Updated: - gsd-oc-tools.cjs: Remove deleted commands from router and help - set-profile.cjs: Remove --reuse flag handling - oc-set-profile.md: Remove --reuse workflow step * feat(quick-6): add profile validation and remove legacy migration - Remove LEGACY_PROFILE_MAP constant - Remove auto-migration block for legacy model_profile - Add profile validation against VALID_PROFILES whitelist - Add current_os_profile tracking in config.json - Keep applyProfileToOpencode for agent config sync * docs(quick-6): complete set-profile validation plan - Create SUMMARY.md with task completion details - Document removed legacy migration code - Document added profile validation - Track verification results * docs(quick-6): update STATE.md with task 6 completion - Add Quick Task 6 to completed tasks table - Update Current Focus to reflect task 6 complete * docs(quick-6): add verification report and update STATE.md * feat(quick-7): Update applyProfileToOpencode to create opencode.json if missing - Replace error-return with creation logic when opencode.json doesn't exist - Create initial structure with $schema and empty agent object - Load and update existing opencode.json when present - Ensure agent object exists in both cases * feat(quick-7): Remove opencode.json existence check from set-profile - Always call applyProfileToOpencode unconditionally - Function now handles both creation and update scenarios - Update comment to reflect create/update behavior * docs(quick-7): Complete set-profile opencode.json creation plan - SUMMARY.md documents changes to oc-config.cjs and set-profile.cjs - STATE.md updated with Quick Task 7 completion - Added key decision about create-or-update pattern * docs: Update STATE.md and workflow for Quick Task 7 completion - Update Quick Task 7 record with correct commit hash (f80ec5a) - Remove migration mention from oc-set-profile workflow - Update session continuity with task 7 focus * fix(set-profile): apply profile changes in non-interactive mode When a profile name is passed as argument, the command now applies the profile changes using current models instead of just outputting a prompt and exiting. * fix(oc-config): generate agent configs with object format {model: id} Always use object format for agent configurations instead of plain strings. * feat(15-01): fix config.json schema and key handling - Use current_oc_profile key (NOT current_os_profile) - Auto-migrate current_os_profile → current_oc_profile if old key exists - Read from profiles.presets.{profile_name}.models structure - Only modify current_oc_profile and profiles keys - Support creating current_oc_profile key if profile name provided * feat(15-01): implement two operation modes and model validation - Mode 1 (no profile name): validates current profile and applies - Mode 2 (profile name provided): validates and applies specified profile - Model validation BEFORE any file modifications using getModelCatalog() - Collects ALL invalid models (doesn't stop at first failure) - Structured JSON output with success/error format - Error codes: PROFILE_NOT_FOUND, INVALID_MODELS, MISSING_CURRENT_PROFILE, CONFIG_NOT_FOUND - Support --raw flag for simplified output * fix(15-01): add migration for current_os_profile key - Add inline migration from current_os_profile → current_oc_profile - Write migrated config back to file - Log migration message to console * docs(15-01): complete fix-set-profile-script plan - Create SUMMARY.md with execution details - Update STATE.md with Phase 15 Plan 01 completion - Update ROADMAP.md progress - Add key decisions to accumulated context - Record performance metrics (23min, 7 tasks, 2 files) * docs(phase-15): update workflow and config after set-profile fix - Simplify oc-set-profile.md workflow, remove migration step - Add newline at end of opencode.json * feat(16-01): create oc-profile-config.cjs library for oc_config.json operations - Export loadOcProfileConfig(cwd) for loading .planning/oc_config.json - Export validateProfile(config, profileName, validModels) for validation - Export applyProfileWithValidation(cwd, profileName, options) for atomic updates - Implement pre-flight validation before file modifications - Support dry-run mode for previewing changes - Atomic transaction with rollback on opencode.json failure - Error codes: CONFIG_NOT_FOUND, INVALID_JSON, PROFILE_NOT_FOUND, INVALID_MODELS, INCOMPLETE_PROFILE - Use oc-core.cjs for output, error, createBackup utilities - Use oc-models.cjs for getModelCatalog whitelist - Use oc-config.cjs applyProfileToOpencode for opencode.json updates * test(16-01): add comprehensive unit tests for oc-profile-config.cjs - Create 18 test cases covering all three exported functions - Test loadOcProfileConfig: CONFIG_NOT_FOUND, INVALID_JSON, valid file - Test validateProfile: valid profiles, PROFILE_NOT_FOUND, INVALID_MODELS, INCOMPLETE_PROFILE - Test applyProfileWithValidation: dry-run, backups, atomic updates, rollback, inline profiles - Test getAgentsForProfile helper function - Test ERROR_CODES exports - Use Vitest framework with ESM syntax - Create test fixtures for valid and invalid configs - Update vitest.config.js to include new test files - All 18 tests pass (100% pass rate) * docs(16-01): complete oc-profile-config.cjs library plan - Created SUMMARY.md with execution details - Updated STATE.md: Phase 16 Plan 01 complete, Phase 16 In Progress (1/3) - Updated ROADMAP.md: Plan progress for Phase 16 - All 9 CONTEXT requirements implemented - Duration: 11 min, 2 tasks, 6 files - Commits: 4d3e985 (library), d1db5a2 (tests) * feat(16-02): create get-profile.cjs command with two operation modes - Mode 1 (no params): Returns current profile from oc_config.json - Mode 2 (profile name): Returns specified profile from oc_config.json - JSON output format with --raw and --verbose flags - Structured JSON errors for MISSING_CURRENT_PROFILE, PROFILE_NOT_FOUND, CONFIG_NOT_FOUND - Read-only operation, no file modifications * test(16-02): add unit tests for get-profile.cjs with 16 test cases - Mode 1 tests: current profile retrieval, error handling - Mode 2 tests: specific profile retrieval, works without current_oc_profile - --raw flag tests: output without JSON envelope - --verbose flag tests: diagnostic output to stderr - Error format tests: structured JSON errors - 100% pass rate (16/16 tests) fix(16-02): correct raw output handling in oc-core.cjs output function - Bug: raw mode was double-stringifying JSON output - Fix: use rawValue directly when raw=true instead of stringify again * chore(16-02): register get-profile command in gsd-oc-tools.cjs - Add get-profile to help text with description - Add command case in switch statement - Add usage examples with and without profile name - Add --raw flag example * docs(16-02): complete get-profile plan execution - Created 16-02-SUMMARY.md with execution details - Updated STATE.md: Plan 02 complete, added metrics and decisions - Updated ROADMAP.md: Phase 16 now 2/3 plans executed - All requirements satisfied: CONTEXT-01, CONTEXT-02, CONTEXT-08, CONTEXT-09 - 16/16 tests passing * feat(16-03): create set-profile-phase16.cjs with three operation modes - Mode 1: validates and applies current profile from oc_config.json - Mode 2: switches to specified profile with validation - Mode 3: creates new profile from inline JSON definition - Pre-flight validation before any file modifications - Atomic transaction with rollback on failure - Dry-run mode for previewing changes - Structured JSON output with error codes * test(16-03): add comprehensive unit tests for set-profile-phase16.cjs - Test Mode 1: validates current profile - Test Mode 2: switches to specified profile - Test Mode 3: creates new profile from inline JSON - Test dry-run mode for all three modes - Test atomic transaction with rollback - Test error handling and validation order - 30+ test cases covering all scenarios * feat(16-03): create pivot-profile.cjs as alias for set-profile-phase16 - Thin wrapper calling setProfilePhase16(cwd, args) - Alternative command name for user preference - No duplicate code or separate tests needed * feat(16-03): register set-profile-phase16 and pivot-profile commands - Add command routing for set-profile-phase16 - Add command routing for pivot-profile alias - Update help text with new commands and examples - Document three operation modes in help * docs(16-03): update STATE.md with Plan 03 completion * feat(16-04): create pivot-profile.test.cjs with 11 unit tests - Tests verify pivotProfile function is exported correctly - Tests verify delegation to setProfilePhase16 with all 3 modes - Tests verify --dry-run flag handling - Tests verify error handling for invalid profiles - All 11 tests pass (100% pass rate) - Test file: 276 lines (target: 30+ lines) - Follows same pattern as get-profile.test.cjs - Mocks console.log, console.error, and process.exit - Uses isolated temp directories for test isolation * docs(16-04): complete pivot-profile test coverage plan - Created 16-04-SUMMARY.md with execution results - Updated STATE.md: Phase 16 Plan 04 complete - Updated ROADMAP.md: Phase 16 now 4/4 plans complete (100%) - Closed verification gap: pivot-profile.test.cjs now exists with 11 passing tests - All CONTEXT-09 requirements satisfied * Update STATE.md and oc-set-profile.md with backup files * Refactor: Rename set-profile-phase16.cjs to set-profile.cjs and update documentation - Renamed set-profile-phase16.cjs to set-profile.cjs as the main profile command - Removed obsolete pivot-profile.cjs and set-profile-phase16.cjs files - Removed set-profile-phase16 and pivot-profile command references from gsd-oc-tools.cjs - Updated all inline filename references to match new naming scheme - Restored proper test file named set-profile.test.cjs from phase16 version * Update oc-set-profile workflow with new command structure - Updated workflow to reflect changes in set-profile command usage - Modified command examples to use new get-profile and inline JSON profile syntax - Updated step-by-step instructions for profile handling to match new implementation - Removed outdated validation steps and update steps that are now handled differently - Corrected terminology and documentation to reflect current code structure * Update update-opencode-json.cjs to use oc_config.json instead of config.json - Modify update-opencode-json.cjs to load from .planning/oc_config.json instead of .planning/config.json - Update all references to use the new config structure with current_oc_profile and profiles.presets - Modify main entry documentation to reflect new config source in gsd-oc-tools.cjs * Create check-oc-config-json command with new schema support - Renamed check-config-json.cjs to check-oc-config-json.cjs - Updated implementation to support oc_config.json instead of config.json - Updated config schema validation to support profiles.presets structure - Updated main router to support check-oc-config-json command - Updated help text to reflect new file structure and migration information * Update oc-set-profile workflow and clean backup files - Updated the oc-set-profile workflow to correspond with new command structure - Removed obsolete backup files that were no longer needed - Kept the workflow documentation in sync with the codebase changes * Refactor oc-set-profile workflow - Fix step numbering (was 5→7) - Update file reference to .planning/oc_config.json - Fix broken JSON command (missing closing brace) - Remove verbose agent listing examples - Define reusable Output Format template - Clarify flow branching for positional vs interactive paths - Streamline from 287 to 158 lines (45% reduction) * fix: set-profile allows updating existing profiles via inline JSON Root cause: PROFILE_EXISTS check at lines 196-198 prevented updating existing profiles when using inline JSON syntax (profileName:JSON). This check was appropriate for preventing accidental duplicates but blocked legitimate use case of updating profile definitions. Fix: Removed the unconditional PROFILE_EXISTS check. Users can now update existing profiles by running set-profile with inline JSON syntax. * Update smart profile agent models - Planning & Execution: qwen3-coder-plus - Verification: MiniMax-M2.5 * Refactor oc-check-profile workflow for clarity and read-only enforcement - Restructure from purpose/process to role/context/behavior/notes format - Add explicit read-only constraint: never modify files or fix issues - Update file references from config.json to oc_config.json - Document JSON response shapes for both validation commands - Remove manual editing option, recommend only /gsd-set-profile - Add CONFIG_NOT_FOUND handling with friendly messaging - Remove verbose step (handled internally by CLI tools) - oc-set-profile.md: Add note about restarting opencode after changes - Cleanup: Remove oc-set-profile-by-qwen.md * Enhance profile validation with severity classification and update settings - Update oc-check-profile.md with severity levels (OK/WARNING/ERROR) - Change model profile option from 'Custom' to 'Genius' - Add set-profile workflow reference in settings.md - Add new exclude patterns and translation pattern in config.json - Fix comment capitalization in CJS library files * Add gsd-check-profile command and update configuration * Add CHANGELOG entry for v1.20.3 and update README Document v1.20.3 release with gsd-oc-tools.cjs CLI, profile management system, validation commands, and vitest testing infrastructure. Add README section explaining new simple/smart/genius profile system and migration from original GSD model profile approach. * Add allow-read-config command for GSD external directory permission - New command: allow-read-config adds external_directory permission to opencode.json - Permission pattern: ~/.config/opencode/get-shit-done/** for recursive access - Supports --dry-run and --verbose flags - Automatic backup creation before modifying existing files - Idempotent operation detects existing permissions - Integrated into oc-set-profile workflow as Step 0 - Test suite with 5 passing tests - Updated CLI help and documentation * Add v1.20.4 CHANGELOG entry for allow-read-config command - Document allow-read-config command in CHANGELOG.md - Add external_directory permission to opencode.json for GSD config access * chore: bump package.json to v1.20.4
1 parent a7ae711 commit 4527186

7 files changed

Lines changed: 553 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.20.4] - 2026-03-05
9+
10+
Overview: Added allow-read-config command to gsd-oc-tools.cjs for managing external_directory permissions. Introduced automated GSD config folder access configuration with comprehensive test coverage and workflow integration.
11+
12+
### Added
13+
14+
- allow-read-config.cjs command for adding external_directory permission to read GSD config folder in `gsd-opencode/get-shit-done/bin/gsd-oc-commands/allow-read-config.cjs`
15+
- Comprehensive test suite for allow-read-config command with 5 tests covering permission creation, idempotency, dry-run mode, backup creation, and verbose output in `gsd-opencode/get-shit-done/bin/test/allow-read-config.test.cjs`
16+
- GSD config read permission step in oc-set-profile.md workflow to ensure access to `~/.config/opencode/get-shit-done/` in `gsd-opencode/get-shit-done/workflows/oc-set-profile.md`
17+
18+
### Changed
19+
20+
- Updated gsd-oc-tools.cjs help text and command routing to include allow-read-config command in `gsd-opencode/get-shit-done/bin/gsd-oc-tools.cjs`
21+
- Updated opencode.json with external_directory permission for `/Users/roki/.config/opencode/get-shit-done/**` in `opencode.json`
22+
823
## [1.20.3] - 2026-03-03
924

1025
Overview: Major CLI tools release introducing gsd-oc-tools.cjs with comprehensive profile management, validation commands, and atomic transaction support. Added separate oc_config.json for profile configuration, pre-flight model validation, and vitest testing infrastructure.
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
/**
2+
* allow-read-config.cjs — Add external_directory permission to read GSD config folder
3+
*
4+
* Creates or updates local opencode.json with permission to access:
5+
* ~/.config/opencode/get-shit-done/
6+
*
7+
* This allows gsd-opencode commands to read workflow files, templates, and
8+
* configuration from the global GSD installation directory.
9+
*
10+
* Usage:
11+
* node allow-read-config.cjs # Add read permission
12+
* node allow-read-config.cjs --dry-run # Preview changes
13+
* node allow-read-config.cjs --verbose # Verbose output
14+
*/
15+
16+
const fs = require('fs');
17+
const path = require('path');
18+
const os = require('os');
19+
const { output, error, createBackup } = require('../gsd-oc-lib/oc-core.cjs');
20+
21+
/**
22+
* Error codes for allow-read-config operations
23+
*/
24+
const ERROR_CODES = {
25+
WRITE_FAILED: 'WRITE_FAILED',
26+
APPLY_FAILED: 'APPLY_FAILED',
27+
ROLLBACK_FAILED: 'ROLLBACK_FAILED',
28+
INVALID_ARGS: 'INVALID_ARGS'
29+
};
30+
31+
/**
32+
* Get the GSD config directory path
33+
* Uses environment variable if set, otherwise defaults to ~/.config/opencode/get-shit-done
34+
*
35+
* @returns {string} GSD config directory path
36+
*/
37+
function getGsdConfigDir() {
38+
const envDir = process.env.OPENCODE_CONFIG_DIR;
39+
if (envDir) {
40+
return envDir;
41+
}
42+
43+
const homeDir = os.homedir();
44+
return path.join(homeDir, '.config', 'opencode', 'get-shit-done');
45+
}
46+
47+
/**
48+
* Build the external_directory permission pattern
49+
*
50+
* @param {string} gsdDir - GSD config directory
51+
* @returns {string} Permission pattern with wildcard
52+
*/
53+
function buildPermissionPattern(gsdDir) {
54+
// Use ** for recursive matching (all subdirectories and files)
55+
return `${gsdDir}/**`;
56+
}
57+
58+
/**
59+
* Check if permission already exists in opencode.json
60+
*
61+
* @param {Object} opencodeData - Parsed opencode.json content
62+
* @param {string} pattern - Permission pattern to check
63+
* @returns {boolean} True if permission exists
64+
*/
65+
function permissionExists(opencodeData, pattern) {
66+
const permissions = opencodeData.permission;
67+
68+
if (!permissions) {
69+
return false;
70+
}
71+
72+
const externalDirPerms = permissions.external_directory;
73+
if (!externalDirPerms || typeof externalDirPerms !== 'object') {
74+
return false;
75+
}
76+
77+
// Check if the pattern exists and is set to "allow"
78+
return externalDirPerms[pattern] === 'allow';
79+
}
80+
81+
/**
82+
* Main command function
83+
*
84+
* @param {string} cwd - Current working directory
85+
* @param {string[]} args - Command line arguments
86+
*/
87+
function allowReadConfig(cwd, args) {
88+
const verbose = args.includes('--verbose');
89+
const dryRun = args.includes('--dry-run');
90+
const raw = args.includes('--raw');
91+
92+
const log = verbose ? (...args) => console.error('[allow-read-config]', ...args) : () => {};
93+
94+
const opencodePath = path.join(cwd, 'opencode.json');
95+
const backupsDir = path.join(cwd, '.planning', 'backups');
96+
const gsdConfigDir = getGsdConfigDir();
97+
const permissionPattern = buildPermissionPattern(gsdConfigDir);
98+
99+
log('Starting allow-read-config command');
100+
log(`GSD config directory: ${gsdConfigDir}`);
101+
log(`Permission pattern: ${permissionPattern}`);
102+
103+
// Check for invalid arguments
104+
const validFlags = ['--verbose', '--dry-run', '--raw'];
105+
const invalidArgs = args.filter(arg =>
106+
arg.startsWith('--') && !validFlags.includes(arg)
107+
);
108+
109+
if (invalidArgs.length > 0) {
110+
error(`Unknown arguments: ${invalidArgs.join(', ')}`, 'INVALID_ARGS');
111+
}
112+
113+
// Load or create opencode.json
114+
let opencodeData;
115+
let fileExisted = false;
116+
117+
if (fs.existsSync(opencodePath)) {
118+
try {
119+
const content = fs.readFileSync(opencodePath, 'utf8');
120+
opencodeData = JSON.parse(content);
121+
fileExisted = true;
122+
log('Loaded existing opencode.json');
123+
} catch (err) {
124+
error(`Failed to parse opencode.json: ${err.message}`, 'INVALID_JSON');
125+
}
126+
} else {
127+
// Create initial opencode.json structure
128+
opencodeData = {
129+
"$schema": "https://opencode.ai/config.json"
130+
};
131+
log('Creating new opencode.json');
132+
}
133+
134+
// Check if permission already exists
135+
const exists = permissionExists(opencodeData, permissionPattern);
136+
137+
if (exists) {
138+
log('Permission already exists');
139+
output({
140+
success: true,
141+
data: {
142+
dryRun: dryRun,
143+
action: 'permission_exists',
144+
pattern: permissionPattern,
145+
message: 'Permission already configured'
146+
}
147+
});
148+
process.exit(0);
149+
}
150+
151+
// Dry-run mode - preview changes
152+
if (dryRun) {
153+
log('Dry-run mode - no changes will be made');
154+
155+
const changes = [];
156+
if (!fileExisted) {
157+
changes.push('Create opencode.json');
158+
}
159+
changes.push(`Add external_directory permission: ${permissionPattern}`);
160+
161+
output({
162+
success: true,
163+
data: {
164+
dryRun: true,
165+
action: 'add_permission',
166+
pattern: permissionPattern,
167+
gsdConfigDir: gsdConfigDir,
168+
changes: changes,
169+
message: fileExisted ? 'Would update opencode.json' : 'Would create opencode.json'
170+
}
171+
});
172+
process.exit(0);
173+
}
174+
175+
// Create backup if file exists
176+
let backupPath = null;
177+
if (fileExisted) {
178+
// Ensure backup directory exists
179+
if (!fs.existsSync(backupsDir)) {
180+
fs.mkdirSync(backupsDir, { recursive: true });
181+
}
182+
183+
backupPath = createBackup(opencodePath, backupsDir);
184+
log(`Backup created: ${backupPath}`);
185+
}
186+
187+
// Initialize permission structure if needed
188+
if (!opencodeData.permission) {
189+
opencodeData.permission = {};
190+
}
191+
192+
if (!opencodeData.permission.external_directory) {
193+
opencodeData.permission.external_directory = {};
194+
}
195+
196+
// Add the permission
197+
opencodeData.permission.external_directory[permissionPattern] = 'allow';
198+
199+
log('Permission added to opencode.json');
200+
201+
// Write updated opencode.json
202+
try {
203+
fs.writeFileSync(opencodePath, JSON.stringify(opencodeData, null, 2) + '\n', 'utf8');
204+
log('Updated opencode.json');
205+
} catch (err) {
206+
// Rollback if backup exists
207+
if (backupPath) {
208+
try {
209+
fs.copyFileSync(backupPath, opencodePath);
210+
} catch (rollbackErr) {
211+
error(
212+
`Failed to write opencode.json AND failed to rollback: ${rollbackErr.message}`,
213+
'ROLLBACK_FAILED'
214+
);
215+
}
216+
}
217+
error(`Failed to write opencode.json: ${err.message}`, 'WRITE_FAILED');
218+
}
219+
220+
output({
221+
success: true,
222+
data: {
223+
action: 'add_permission',
224+
pattern: permissionPattern,
225+
gsdConfigDir: gsdConfigDir,
226+
opencodePath: opencodePath,
227+
backup: backupPath,
228+
created: !fileExisted,
229+
message: fileExisted ? 'opencode.json updated' : 'opencode.json created'
230+
}
231+
});
232+
process.exit(0);
233+
}
234+
235+
module.exports = allowReadConfig;

gsd-opencode/get-shit-done/bin/gsd-oc-tools.cjs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
* validate-models Validate model IDs against opencode catalog
1717
* set-profile Switch profile with interactive model selection
1818
* get-profile Get current profile or specific profile from oc_config.json
19+
* allow-read-config Add external_directory permission to read GSD config folder
1920
* help Show this help message
2021
*/
2122

@@ -50,12 +51,13 @@ Available Commands:
5051
validate-models Validate one or more model IDs against opencode catalog
5152
set-profile Switch profile with interactive model selection wizard
5253
get-profile Get current profile or specific profile from oc_config.json
54+
allow-read-config Add external_directory permission to read ~/.config/opencode/get-shit-done/**
5355
help Show this help message
5456
5557
Options:
5658
--verbose Enable verbose output (stderr)
57-
--raw Output raw values instead of JSON envelope
58-
--dry-run Preview changes without applying (update-opencode-json)
59+
--raw Output raw value instead of JSON envelope
60+
--dry-run Preview changes without applying (update-opencode-json, allow-read-config)
5961
6062
Examples:
6163
node gsd-oc-tools.cjs check-opencode-json
@@ -66,6 +68,8 @@ Examples:
6668
node gsd-oc-tools.cjs get-profile
6769
node gsd-oc-tools.cjs get-profile genius
6870
node gsd-oc-tools.cjs get-profile --raw
71+
node gsd-oc-tools.cjs allow-read-config
72+
node gsd-oc-tools.cjs allow-read-config --dry-run
6973
`.trim();
7074

7175
console.log(helpText);
@@ -121,9 +125,11 @@ switch (command) {
121125
break;
122126
}
123127

124-
125-
126-
128+
case 'allow-read-config': {
129+
const allowReadConfig = require('./gsd-oc-commands/allow-read-config.cjs');
130+
allowReadConfig(cwd, flags);
131+
break;
132+
}
127133

128134
default:
129135
error(`Unknown command: ${command}\nRun 'node gsd-oc-tools.cjs help' for available commands.`);

0 commit comments

Comments
 (0)