Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
640934f
feat(14-01): create core infrastructure libraries (oc-core.cjs, oc-mo…
rokicool Mar 1, 2026
5c9cbc9
feat(14-01): create check-opencode-json command
rokicool Mar 1, 2026
481f8db
feat(14-01): create check-config-json command
rokicool Mar 1, 2026
369fdf3
feat(14-01): create gsd-oc-tools.cjs main entry point
rokicool Mar 1, 2026
7124aa8
feat(14-02): create oc-config.cjs library module
rokicool Mar 1, 2026
6db03b3
feat(14-02): create update-opencode-json command
rokicool Mar 1, 2026
4462595
feat(14-02): register update-opencode-json command
rokicool Mar 1, 2026
a9ca34e
fix(14-02): support profiles.models profile structure
rokicool Mar 1, 2026
037ab0d
docs(14-02): complete update-opencode-json plan
rokicool Mar 1, 2026
2123c7b
feat(oc-tools): create gsd-oc-commands and gsd-oc-lib directories
rokicool Mar 1, 2026
59e346d
feat(quick-4-01): enhance applyProfileToOpencode to return model IDs
rokicool Mar 1, 2026
c2beb2f
feat(quick-4-01): add model IDs to command output
rokicool Mar 1, 2026
bdc0f65
docs(quick-4-01): complete extend-return-of-update-opencode-json plan
rokicool Mar 1, 2026
c736845
feat(quick-5-01): create gsd-oc-check-profile validation workflow
rokicool Mar 1, 2026
3711fa1
docs(quick-5): complete profile validation workflow plan
rokicool Mar 1, 2026
ce6455a
config: switch to simple profile with qwen3.5-plus for all stages
rokicool Mar 1, 2026
59545c2
refactor(workflows): rename gsd-oc-check-profile to oc-check-profile …
rokicool Mar 1, 2026
f9d7281
Extend gsd-oc-tools with profile management commands
rokicool Mar 1, 2026
b280e8f
Fix gsd-oc-tools.cjs paths in workflows
rokicool Mar 1, 2026
2917880
Refactor check-config-json and remove unused commands
rokicool Mar 2, 2026
837b2bc
feat(quick-6): add profile validation and remove legacy migration
rokicool Mar 2, 2026
8f9eac7
docs(quick-6): complete set-profile validation plan
rokicool Mar 2, 2026
daf2e11
docs(quick-6): update STATE.md with task 6 completion
rokicool Mar 2, 2026
5b11eec
docs(quick-6): add verification report and update STATE.md
rokicool Mar 2, 2026
754528d
feat(quick-7): Update applyProfileToOpencode to create opencode.json …
rokicool Mar 2, 2026
b9f5fe9
feat(quick-7): Remove opencode.json existence check from set-profile
rokicool Mar 2, 2026
f80ec5a
docs(quick-7): Complete set-profile opencode.json creation plan
rokicool Mar 2, 2026
04cedf5
docs: Update STATE.md and workflow for Quick Task 7 completion
rokicool Mar 2, 2026
57510b7
fix(set-profile): apply profile changes in non-interactive mode
rokicool Mar 2, 2026
93a43ed
fix(oc-config): generate agent configs with object format {model: id}
rokicool Mar 2, 2026
c4ad78d
feat(15-01): fix config.json schema and key handling
rokicool Mar 2, 2026
93c6c50
feat(15-01): implement two operation modes and model validation
rokicool Mar 2, 2026
9afe34d
fix(15-01): add migration for current_os_profile key
rokicool Mar 2, 2026
f63e988
docs(15-01): complete fix-set-profile-script plan
rokicool Mar 2, 2026
9dd58de
docs(phase-15): update workflow and config after set-profile fix
rokicool Mar 2, 2026
4d3e985
feat(16-01): create oc-profile-config.cjs library for oc_config.json …
rokicool Mar 3, 2026
d1db5a2
test(16-01): add comprehensive unit tests for oc-profile-config.cjs
rokicool Mar 3, 2026
a3d71f0
docs(16-01): complete oc-profile-config.cjs library plan
rokicool Mar 3, 2026
7516b11
feat(16-02): create get-profile.cjs command with two operation modes
rokicool Mar 3, 2026
4799fd8
test(16-02): add unit tests for get-profile.cjs with 16 test cases
rokicool Mar 3, 2026
a630614
chore(16-02): register get-profile command in gsd-oc-tools.cjs
rokicool Mar 3, 2026
d9b8de5
docs(16-02): complete get-profile plan execution
rokicool Mar 3, 2026
2faeafb
feat(16-03): create set-profile-phase16.cjs with three operation modes
rokicool Mar 3, 2026
76f4426
test(16-03): add comprehensive unit tests for set-profile-phase16.cjs
rokicool Mar 3, 2026
d443d3a
feat(16-03): create pivot-profile.cjs as alias for set-profile-phase16
rokicool Mar 3, 2026
a245dbc
feat(16-03): register set-profile-phase16 and pivot-profile commands
rokicool Mar 3, 2026
c4fb44a
docs(16-03): update STATE.md with Plan 03 completion
rokicool Mar 3, 2026
c6e3890
feat(16-04): create pivot-profile.test.cjs with 11 unit tests
rokicool Mar 3, 2026
03232ec
docs(16-04): complete pivot-profile test coverage plan
rokicool Mar 3, 2026
5ec8a51
Update STATE.md and oc-set-profile.md with backup files
rokicool Mar 3, 2026
9f8f0be
Refactor: Rename set-profile-phase16.cjs to set-profile.cjs and updat…
rokicool Mar 3, 2026
c88bbfc
Update oc-set-profile workflow with new command structure
rokicool Mar 3, 2026
c12e253
Update update-opencode-json.cjs to use oc_config.json instead of conf…
rokicool Mar 3, 2026
e476db0
Create check-oc-config-json command with new schema support
rokicool Mar 3, 2026
69605a1
Update oc-set-profile workflow and clean backup files
rokicool Mar 3, 2026
1304afb
Refactor oc-set-profile workflow
rokicool Mar 3, 2026
97fd3e2
fix: set-profile allows updating existing profiles via inline JSON
rokicool Mar 3, 2026
5ad548d
Update smart profile agent models
rokicool Mar 3, 2026
be2b41c
Refactor oc-check-profile workflow for clarity and read-only enforcement
rokicool Mar 3, 2026
e020047
Enhance profile validation with severity classification and update se…
rokicool Mar 3, 2026
8886804
Add gsd-check-profile command and update configuration
rokicool Mar 3, 2026
200bcbf
Add CHANGELOG entry for v1.20.3 and update README
rokicool Mar 3, 2026
363bc12
Add allow-read-config command for GSD external directory permission
rokicool Mar 5, 2026
ae873b3
Add v1.20.4 CHANGELOG entry for allow-read-config command
rokicool Mar 5, 2026
a27a6fa
chore: bump package.json to v1.20.4
rokicool Mar 5, 2026
769a353
Merge branch 'main' into dev
rokicool Mar 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.20.4] - 2026-03-05

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.

### Added

- 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`
- 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`
- 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`

### Changed

- 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`
- Updated opencode.json with external_directory permission for `/Users/roki/.config/opencode/get-shit-done/**` in `opencode.json`

## [1.20.3] - 2026-03-03

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.
Expand Down
235 changes: 235 additions & 0 deletions gsd-opencode/get-shit-done/bin/gsd-oc-commands/allow-read-config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
/**
* allow-read-config.cjs — Add external_directory permission to read GSD config folder
*
* Creates or updates local opencode.json with permission to access:
* ~/.config/opencode/get-shit-done/
*
* This allows gsd-opencode commands to read workflow files, templates, and
* configuration from the global GSD installation directory.
*
* Usage:
* node allow-read-config.cjs # Add read permission
* node allow-read-config.cjs --dry-run # Preview changes
* node allow-read-config.cjs --verbose # Verbose output
*/

const fs = require('fs');
const path = require('path');
const os = require('os');
const { output, error, createBackup } = require('../gsd-oc-lib/oc-core.cjs');

/**
* Error codes for allow-read-config operations
*/
const ERROR_CODES = {
WRITE_FAILED: 'WRITE_FAILED',
APPLY_FAILED: 'APPLY_FAILED',
ROLLBACK_FAILED: 'ROLLBACK_FAILED',
INVALID_ARGS: 'INVALID_ARGS'
};

/**
* Get the GSD config directory path
* Uses environment variable if set, otherwise defaults to ~/.config/opencode/get-shit-done
*
* @returns {string} GSD config directory path
*/
function getGsdConfigDir() {
const envDir = process.env.OPENCODE_CONFIG_DIR;
if (envDir) {
return envDir;
}

const homeDir = os.homedir();
return path.join(homeDir, '.config', 'opencode', 'get-shit-done');
}

/**
* Build the external_directory permission pattern
*
* @param {string} gsdDir - GSD config directory
* @returns {string} Permission pattern with wildcard
*/
function buildPermissionPattern(gsdDir) {
// Use ** for recursive matching (all subdirectories and files)
return `${gsdDir}/**`;
}

/**
* Check if permission already exists in opencode.json
*
* @param {Object} opencodeData - Parsed opencode.json content
* @param {string} pattern - Permission pattern to check
* @returns {boolean} True if permission exists
*/
function permissionExists(opencodeData, pattern) {
const permissions = opencodeData.permission;

if (!permissions) {
return false;
}

const externalDirPerms = permissions.external_directory;
if (!externalDirPerms || typeof externalDirPerms !== 'object') {
return false;
}

// Check if the pattern exists and is set to "allow"
return externalDirPerms[pattern] === 'allow';
}

/**
* Main command function
*
* @param {string} cwd - Current working directory
* @param {string[]} args - Command line arguments
*/
function allowReadConfig(cwd, args) {
const verbose = args.includes('--verbose');
const dryRun = args.includes('--dry-run');
const raw = args.includes('--raw');

const log = verbose ? (...args) => console.error('[allow-read-config]', ...args) : () => {};

const opencodePath = path.join(cwd, 'opencode.json');
const backupsDir = path.join(cwd, '.planning', 'backups');
const gsdConfigDir = getGsdConfigDir();
const permissionPattern = buildPermissionPattern(gsdConfigDir);

log('Starting allow-read-config command');
log(`GSD config directory: ${gsdConfigDir}`);
log(`Permission pattern: ${permissionPattern}`);

// Check for invalid arguments
const validFlags = ['--verbose', '--dry-run', '--raw'];
const invalidArgs = args.filter(arg =>
arg.startsWith('--') && !validFlags.includes(arg)
);

if (invalidArgs.length > 0) {
error(`Unknown arguments: ${invalidArgs.join(', ')}`, 'INVALID_ARGS');
}

// Load or create opencode.json
let opencodeData;
let fileExisted = false;

if (fs.existsSync(opencodePath)) {
try {
const content = fs.readFileSync(opencodePath, 'utf8');
opencodeData = JSON.parse(content);
fileExisted = true;
log('Loaded existing opencode.json');
} catch (err) {
error(`Failed to parse opencode.json: ${err.message}`, 'INVALID_JSON');
}
} else {
// Create initial opencode.json structure
opencodeData = {
"$schema": "https://opencode.ai/config.json"
};
log('Creating new opencode.json');
}

// Check if permission already exists
const exists = permissionExists(opencodeData, permissionPattern);

if (exists) {
log('Permission already exists');
output({
success: true,
data: {
dryRun: dryRun,
action: 'permission_exists',
pattern: permissionPattern,
message: 'Permission already configured'
}
});
process.exit(0);
}

// Dry-run mode - preview changes
if (dryRun) {
log('Dry-run mode - no changes will be made');

const changes = [];
if (!fileExisted) {
changes.push('Create opencode.json');
}
changes.push(`Add external_directory permission: ${permissionPattern}`);

output({
success: true,
data: {
dryRun: true,
action: 'add_permission',
pattern: permissionPattern,
gsdConfigDir: gsdConfigDir,
changes: changes,
message: fileExisted ? 'Would update opencode.json' : 'Would create opencode.json'
}
});
process.exit(0);
}

// Create backup if file exists
let backupPath = null;
if (fileExisted) {
// Ensure backup directory exists
if (!fs.existsSync(backupsDir)) {
fs.mkdirSync(backupsDir, { recursive: true });
}

backupPath = createBackup(opencodePath, backupsDir);
log(`Backup created: ${backupPath}`);
}

// Initialize permission structure if needed
if (!opencodeData.permission) {
opencodeData.permission = {};
}

if (!opencodeData.permission.external_directory) {
opencodeData.permission.external_directory = {};
}

// Add the permission
opencodeData.permission.external_directory[permissionPattern] = 'allow';

log('Permission added to opencode.json');

// Write updated opencode.json
try {
fs.writeFileSync(opencodePath, JSON.stringify(opencodeData, null, 2) + '\n', 'utf8');
log('Updated opencode.json');
} catch (err) {
// Rollback if backup exists
if (backupPath) {
try {
fs.copyFileSync(backupPath, opencodePath);
} catch (rollbackErr) {
error(
`Failed to write opencode.json AND failed to rollback: ${rollbackErr.message}`,
'ROLLBACK_FAILED'
);
}
}
error(`Failed to write opencode.json: ${err.message}`, 'WRITE_FAILED');
}

output({
success: true,
data: {
action: 'add_permission',
pattern: permissionPattern,
gsdConfigDir: gsdConfigDir,
opencodePath: opencodePath,
backup: backupPath,
created: !fileExisted,
message: fileExisted ? 'opencode.json updated' : 'opencode.json created'
}
});
process.exit(0);
}

module.exports = allowReadConfig;
16 changes: 11 additions & 5 deletions gsd-opencode/get-shit-done/bin/gsd-oc-tools.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* validate-models Validate model IDs against opencode catalog
* set-profile Switch profile with interactive model selection
* get-profile Get current profile or specific profile from oc_config.json
* allow-read-config Add external_directory permission to read GSD config folder
* help Show this help message
*/

Expand Down Expand Up @@ -50,12 +51,13 @@ Available Commands:
validate-models Validate one or more model IDs against opencode catalog
set-profile Switch profile with interactive model selection wizard
get-profile Get current profile or specific profile from oc_config.json
allow-read-config Add external_directory permission to read ~/.config/opencode/get-shit-done/**
help Show this help message

Options:
--verbose Enable verbose output (stderr)
--raw Output raw values instead of JSON envelope
--dry-run Preview changes without applying (update-opencode-json)
--raw Output raw value instead of JSON envelope
--dry-run Preview changes without applying (update-opencode-json, allow-read-config)

Examples:
node gsd-oc-tools.cjs check-opencode-json
Expand All @@ -66,6 +68,8 @@ Examples:
node gsd-oc-tools.cjs get-profile
node gsd-oc-tools.cjs get-profile genius
node gsd-oc-tools.cjs get-profile --raw
node gsd-oc-tools.cjs allow-read-config
node gsd-oc-tools.cjs allow-read-config --dry-run
`.trim();

console.log(helpText);
Expand Down Expand Up @@ -121,9 +125,11 @@ switch (command) {
break;
}




case 'allow-read-config': {
const allowReadConfig = require('./gsd-oc-commands/allow-read-config.cjs');
allowReadConfig(cwd, flags);
break;
}

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