mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-05 01:50:27 +08:00
Enhance workflow commands and context management
- Updated `plan.md` to include new fields in context-package.json: prioritized_context, user_intent, priority_tiers, dependency_order, and sorting_rationale. - Added validation for the existence of the prioritized_context field in context-package.json. - Modified user decision flow in task generation to present action choices after planning completion. - Improved context-gathering process in `context-gather.md` to integrate user intent and prioritize context based on user goals. - Revised conflict-resolution documentation to require planning notes records after conflict analysis. - Streamlined task generation in `task-generate-agent.md` to utilize pre-sorted context without redundant sorting. - Removed unused settings persistence functions and corresponding tests from `claude-cli-tools.ts` and `settings-persistence.test.ts`.
This commit is contained in:
@@ -733,66 +733,6 @@ export function getPromptFormat(projectDir: string): 'plain' | 'yaml' | 'json' {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update default model setting
|
||||
* @param projectDir - Project directory path
|
||||
* @param model - Default model name
|
||||
* @returns Updated settings config
|
||||
*/
|
||||
export function setDefaultModel(
|
||||
projectDir: string,
|
||||
model: string
|
||||
): ClaudeCliSettingsConfig {
|
||||
const settings = loadClaudeCliSettings(projectDir);
|
||||
settings.defaultModel = model;
|
||||
saveClaudeCliSettings(projectDir, settings);
|
||||
return settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default model setting
|
||||
* @param projectDir - Project directory path
|
||||
* @returns Current default model or undefined if not set
|
||||
*/
|
||||
export function getDefaultModel(projectDir: string): string | undefined {
|
||||
try {
|
||||
const settings = loadClaudeCliSettings(projectDir);
|
||||
return settings.defaultModel;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update auto-sync enabled setting
|
||||
* @param projectDir - Project directory path
|
||||
* @param enabled - Whether auto-sync is enabled
|
||||
* @returns Updated settings config
|
||||
*/
|
||||
export function setAutoSyncEnabled(
|
||||
projectDir: string,
|
||||
enabled: boolean
|
||||
): ClaudeCliSettingsConfig {
|
||||
const settings = loadClaudeCliSettings(projectDir);
|
||||
settings.autoSyncEnabled = enabled;
|
||||
saveClaudeCliSettings(projectDir, settings);
|
||||
return settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get auto-sync enabled setting
|
||||
* @param projectDir - Project directory path
|
||||
* @returns Current auto-sync status or undefined if not set
|
||||
*/
|
||||
export function getAutoSyncEnabled(projectDir: string): boolean | undefined {
|
||||
try {
|
||||
const settings = loadClaudeCliSettings(projectDir);
|
||||
return settings.autoSyncEnabled;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update smart context enabled setting
|
||||
* @param projectDir - Project directory path
|
||||
|
||||
@@ -1,375 +0,0 @@
|
||||
/**
|
||||
* Unit tests for Settings Persistence Functions
|
||||
*
|
||||
* Tests the new setter/getter functions for ClaudeCliSettingsConfig:
|
||||
* - setPromptFormat / getPromptFormat
|
||||
* - setDefaultModel / getDefaultModel
|
||||
* - setAutoSyncEnabled / getAutoSyncEnabled
|
||||
* - setSmartContextEnabled / getSmartContextEnabled
|
||||
* - setNativeResume / getNativeResume
|
||||
*/
|
||||
|
||||
import { after, afterEach, before, describe, it } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { existsSync, mkdtempSync, rmSync, writeFileSync, readFileSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
|
||||
// Set up isolated test environment
|
||||
const TEST_CCW_HOME = mkdtempSync(join(tmpdir(), 'ccw-settings-test-'));
|
||||
process.env.CCW_DATA_DIR = TEST_CCW_HOME;
|
||||
|
||||
const claudeCliToolsPath = new URL('../dist/tools/claude-cli-tools.js', import.meta.url).href;
|
||||
|
||||
describe('Settings Persistence Functions', async () => {
|
||||
let claudeCliTools: any;
|
||||
const testProjectDir = join(TEST_CCW_HOME, 'test-project');
|
||||
|
||||
before(async () => {
|
||||
claudeCliTools = await import(claudeCliToolsPath);
|
||||
});
|
||||
|
||||
after(() => {
|
||||
rmSync(TEST_CCW_HOME, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Clean up settings file after each test
|
||||
const settingsPath = join(TEST_CCW_HOME, '.claude', 'cli-settings.json');
|
||||
if (existsSync(settingsPath)) {
|
||||
rmSync(settingsPath);
|
||||
}
|
||||
});
|
||||
|
||||
describe('setPromptFormat / getPromptFormat', () => {
|
||||
it('should set and get prompt format', () => {
|
||||
const result = claudeCliTools.setPromptFormat(testProjectDir, 'yaml');
|
||||
assert.equal(result.promptFormat, 'yaml');
|
||||
|
||||
const retrieved = claudeCliTools.getPromptFormat(testProjectDir);
|
||||
assert.equal(retrieved, 'yaml');
|
||||
});
|
||||
|
||||
it('should persist prompt format to file', () => {
|
||||
claudeCliTools.setPromptFormat(testProjectDir, 'json');
|
||||
|
||||
const settingsPath = join(TEST_CCW_HOME, '.claude', 'cli-settings.json');
|
||||
assert.ok(existsSync(settingsPath), 'Settings file should exist');
|
||||
|
||||
const content = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
||||
assert.equal(content.promptFormat, 'json');
|
||||
});
|
||||
|
||||
it('should update existing prompt format', () => {
|
||||
claudeCliTools.setPromptFormat(testProjectDir, 'plain');
|
||||
claudeCliTools.setPromptFormat(testProjectDir, 'yaml');
|
||||
|
||||
const retrieved = claudeCliTools.getPromptFormat(testProjectDir);
|
||||
assert.equal(retrieved, 'yaml');
|
||||
});
|
||||
|
||||
it('should return default when file does not exist', () => {
|
||||
const retrieved = claudeCliTools.getPromptFormat(testProjectDir);
|
||||
assert.equal(retrieved, 'plain');
|
||||
});
|
||||
|
||||
it('should accept all valid format values', () => {
|
||||
const formats: Array<'plain' | 'yaml' | 'json'> = ['plain', 'yaml', 'json'];
|
||||
|
||||
for (const format of formats) {
|
||||
claudeCliTools.setPromptFormat(testProjectDir, format);
|
||||
const retrieved = claudeCliTools.getPromptFormat(testProjectDir);
|
||||
assert.equal(retrieved, format, `Format ${format} should be set correctly`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('setDefaultModel / getDefaultModel', () => {
|
||||
it('should set and get default model', () => {
|
||||
const result = claudeCliTools.setDefaultModel(testProjectDir, 'gemini-2.5-pro');
|
||||
assert.equal(result.defaultModel, 'gemini-2.5-pro');
|
||||
|
||||
const retrieved = claudeCliTools.getDefaultModel(testProjectDir);
|
||||
assert.equal(retrieved, 'gemini-2.5-pro');
|
||||
});
|
||||
|
||||
it('should persist default model to file', () => {
|
||||
claudeCliTools.setDefaultModel(testProjectDir, 'claude-opus-4');
|
||||
|
||||
const settingsPath = join(TEST_CCW_HOME, '.claude', 'cli-settings.json');
|
||||
assert.ok(existsSync(settingsPath), 'Settings file should exist');
|
||||
|
||||
const content = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
||||
assert.equal(content.defaultModel, 'claude-opus-4');
|
||||
});
|
||||
|
||||
it('should update existing default model', () => {
|
||||
claudeCliTools.setDefaultModel(testProjectDir, 'gpt-4.1');
|
||||
claudeCliTools.setDefaultModel(testProjectDir, 'gpt-5.2');
|
||||
|
||||
const retrieved = claudeCliTools.getDefaultModel(testProjectDir);
|
||||
assert.equal(retrieved, 'gpt-5.2');
|
||||
});
|
||||
|
||||
it('should return undefined when not set', () => {
|
||||
const retrieved = claudeCliTools.getDefaultModel(testProjectDir);
|
||||
assert.equal(retrieved, undefined);
|
||||
});
|
||||
|
||||
it('should handle arbitrary model names', () => {
|
||||
const models = ['custom-model-1', 'test-model', 'my-fine-tuned-model'];
|
||||
|
||||
for (const model of models) {
|
||||
claudeCliTools.setDefaultModel(testProjectDir, model);
|
||||
const retrieved = claudeCliTools.getDefaultModel(testProjectDir);
|
||||
assert.equal(retrieved, model, `Model ${model} should be set correctly`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('setAutoSyncEnabled / getAutoSyncEnabled', () => {
|
||||
it('should set and get auto-sync enabled status', () => {
|
||||
const result = claudeCliTools.setAutoSyncEnabled(testProjectDir, true);
|
||||
assert.equal(result.autoSyncEnabled, true);
|
||||
|
||||
const retrieved = claudeCliTools.getAutoSyncEnabled(testProjectDir);
|
||||
assert.equal(retrieved, true);
|
||||
});
|
||||
|
||||
it('should persist auto-sync status to file', () => {
|
||||
claudeCliTools.setAutoSyncEnabled(testProjectDir, false);
|
||||
|
||||
const settingsPath = join(TEST_CCW_HOME, '.claude', 'cli-settings.json');
|
||||
assert.ok(existsSync(settingsPath), 'Settings file should exist');
|
||||
|
||||
const content = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
||||
assert.equal(content.autoSyncEnabled, false);
|
||||
});
|
||||
|
||||
it('should update existing auto-sync status', () => {
|
||||
claudeCliTools.setAutoSyncEnabled(testProjectDir, true);
|
||||
claudeCliTools.setAutoSyncEnabled(testProjectDir, false);
|
||||
|
||||
const retrieved = claudeCliTools.getAutoSyncEnabled(testProjectDir);
|
||||
assert.equal(retrieved, false);
|
||||
});
|
||||
|
||||
it('should return undefined when not set', () => {
|
||||
const retrieved = claudeCliTools.getAutoSyncEnabled(testProjectDir);
|
||||
assert.equal(retrieved, undefined);
|
||||
});
|
||||
|
||||
it('should toggle between true and false', () => {
|
||||
claudeCliTools.setAutoSyncEnabled(testProjectDir, true);
|
||||
let retrieved = claudeCliTools.getAutoSyncEnabled(testProjectDir);
|
||||
assert.equal(retrieved, true);
|
||||
|
||||
claudeCliTools.setAutoSyncEnabled(testProjectDir, false);
|
||||
retrieved = claudeCliTools.getAutoSyncEnabled(testProjectDir);
|
||||
assert.equal(retrieved, false);
|
||||
|
||||
claudeCliTools.setAutoSyncEnabled(testProjectDir, true);
|
||||
retrieved = claudeCliTools.getAutoSyncEnabled(testProjectDir);
|
||||
assert.equal(retrieved, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setSmartContextEnabled / getSmartContextEnabled', () => {
|
||||
it('should set and get smart context enabled status', () => {
|
||||
const result = claudeCliTools.setSmartContextEnabled(testProjectDir, true);
|
||||
assert.equal(result.smartContext.enabled, true);
|
||||
|
||||
const retrieved = claudeCliTools.getSmartContextEnabled(testProjectDir);
|
||||
assert.equal(retrieved, true);
|
||||
});
|
||||
|
||||
it('should persist smart context status to file', () => {
|
||||
claudeCliTools.setSmartContextEnabled(testProjectDir, true);
|
||||
|
||||
const settingsPath = join(TEST_CCW_HOME, '.claude', 'cli-settings.json');
|
||||
assert.ok(existsSync(settingsPath), 'Settings file should exist');
|
||||
|
||||
const content = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
||||
assert.equal(content.smartContext.enabled, true);
|
||||
});
|
||||
|
||||
it('should preserve other smartContext properties', () => {
|
||||
// First, load settings to check default maxFiles
|
||||
const settings = claudeCliTools.loadClaudeCliSettings(testProjectDir);
|
||||
const defaultMaxFiles = settings.smartContext.maxFiles;
|
||||
|
||||
claudeCliTools.setSmartContextEnabled(testProjectDir, true);
|
||||
|
||||
const settingsPath = join(TEST_CCW_HOME, '.claude', 'cli-settings.json');
|
||||
const content = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
||||
|
||||
assert.equal(content.smartContext.enabled, true);
|
||||
assert.equal(content.smartContext.maxFiles, defaultMaxFiles, 'maxFiles should be preserved');
|
||||
});
|
||||
|
||||
it('should return false when not set', () => {
|
||||
const retrieved = claudeCliTools.getSmartContextEnabled(testProjectDir);
|
||||
assert.equal(retrieved, false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setNativeResume / getNativeResume', () => {
|
||||
it('should set and get native resume status', () => {
|
||||
const result = claudeCliTools.setNativeResume(testProjectDir, false);
|
||||
assert.equal(result.nativeResume, false);
|
||||
|
||||
const retrieved = claudeCliTools.getNativeResume(testProjectDir);
|
||||
assert.equal(retrieved, false);
|
||||
});
|
||||
|
||||
it('should persist native resume status to file', () => {
|
||||
claudeCliTools.setNativeResume(testProjectDir, false);
|
||||
|
||||
const settingsPath = join(TEST_CCW_HOME, '.claude', 'cli-settings.json');
|
||||
assert.ok(existsSync(settingsPath), 'Settings file should exist');
|
||||
|
||||
const content = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
||||
assert.equal(content.nativeResume, false);
|
||||
});
|
||||
|
||||
it('should return true when not set (default)', () => {
|
||||
const retrieved = claudeCliTools.getNativeResume(testProjectDir);
|
||||
assert.equal(retrieved, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Multiple settings updates', () => {
|
||||
it('should handle multiple settings updates in sequence', () => {
|
||||
claudeCliTools.setPromptFormat(testProjectDir, 'yaml');
|
||||
claudeCliTools.setDefaultModel(testProjectDir, 'gemini-2.5-pro');
|
||||
claudeCliTools.setAutoSyncEnabled(testProjectDir, true);
|
||||
claudeCliTools.setSmartContextEnabled(testProjectDir, true);
|
||||
claudeCliTools.setNativeResume(testProjectDir, false);
|
||||
|
||||
assert.equal(claudeCliTools.getPromptFormat(testProjectDir), 'yaml');
|
||||
assert.equal(claudeCliTools.getDefaultModel(testProjectDir), 'gemini-2.5-pro');
|
||||
assert.equal(claudeCliTools.getAutoSyncEnabled(testProjectDir), true);
|
||||
assert.equal(claudeCliTools.getSmartContextEnabled(testProjectDir), true);
|
||||
assert.equal(claudeCliTools.getNativeResume(testProjectDir), false);
|
||||
});
|
||||
|
||||
it('should preserve existing settings when updating one', () => {
|
||||
claudeCliTools.setPromptFormat(testProjectDir, 'json');
|
||||
claudeCliTools.setDefaultModel(testProjectDir, 'test-model');
|
||||
|
||||
// Update only auto-sync
|
||||
claudeCliTools.setAutoSyncEnabled(testProjectDir, true);
|
||||
|
||||
// Verify previous settings are preserved
|
||||
assert.equal(claudeCliTools.getPromptFormat(testProjectDir), 'json');
|
||||
assert.equal(claudeCliTools.getDefaultModel(testProjectDir), 'test-model');
|
||||
assert.equal(claudeCliTools.getAutoSyncEnabled(testProjectDir), true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Performance', () => {
|
||||
it('should complete setter operations in under 10ms', () => {
|
||||
const operations = [
|
||||
() => claudeCliTools.setPromptFormat(testProjectDir, 'yaml'),
|
||||
() => claudeCliTools.setDefaultModel(testProjectDir, 'test-model'),
|
||||
() => claudeCliTools.setAutoSyncEnabled(testProjectDir, true),
|
||||
() => claudeCliTools.setSmartContextEnabled(testProjectDir, true),
|
||||
() => claudeCliTools.setNativeResume(testProjectDir, false),
|
||||
];
|
||||
|
||||
for (const operation of operations) {
|
||||
const start = Date.now();
|
||||
operation();
|
||||
const duration = Date.now() - start;
|
||||
assert.ok(duration < 10, `Operation should complete in under 10ms (took ${duration}ms)`);
|
||||
}
|
||||
});
|
||||
|
||||
it('should complete getter operations in under 10ms', () => {
|
||||
// Set up some data first
|
||||
claudeCliTools.setPromptFormat(testProjectDir, 'yaml');
|
||||
claudeCliTools.setDefaultModel(testProjectDir, 'test-model');
|
||||
claudeCliTools.setAutoSyncEnabled(testProjectDir, true);
|
||||
|
||||
const operations = [
|
||||
() => claudeCliTools.getPromptFormat(testProjectDir),
|
||||
() => claudeCliTools.getDefaultModel(testProjectDir),
|
||||
() => claudeCliTools.getAutoSyncEnabled(testProjectDir),
|
||||
() => claudeCliTools.getSmartContextEnabled(testProjectDir),
|
||||
() => claudeCliTools.getNativeResume(testProjectDir),
|
||||
];
|
||||
|
||||
for (const operation of operations) {
|
||||
const start = Date.now();
|
||||
operation();
|
||||
const duration = Date.now() - start;
|
||||
assert.ok(duration < 10, `Operation should complete in under 10ms (took ${duration}ms)`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('File corruption handling', () => {
|
||||
it('should handle invalid JSON gracefully', () => {
|
||||
const settingsPath = join(TEST_CCW_HOME, '.claude', 'cli-settings.json');
|
||||
const claudeDir = join(TEST_CCW_HOME, '.claude');
|
||||
|
||||
// Create .claude directory if it doesn't exist
|
||||
if (!existsSync(claudeDir)) {
|
||||
mkdtempSync(claudeDir);
|
||||
}
|
||||
|
||||
// Write invalid JSON
|
||||
writeFileSync(settingsPath, '{invalid json}', 'utf-8');
|
||||
|
||||
// Getters should return defaults
|
||||
assert.equal(claudeCliTools.getPromptFormat(testProjectDir), 'plain');
|
||||
assert.equal(claudeCliTools.getDefaultModel(testProjectDir), undefined);
|
||||
assert.equal(claudeCliTools.getAutoSyncEnabled(testProjectDir), undefined);
|
||||
});
|
||||
|
||||
it('should recover from corrupted file by overwriting', () => {
|
||||
const settingsPath = join(TEST_CCW_HOME, '.claude', 'cli-settings.json');
|
||||
const claudeDir = join(TEST_CCW_HOME, '.claude');
|
||||
|
||||
// Create .claude directory if it doesn't exist
|
||||
if (!existsSync(claudeDir)) {
|
||||
mkdtempSync(claudeDir);
|
||||
}
|
||||
|
||||
// Write invalid JSON
|
||||
writeFileSync(settingsPath, '{invalid json}', 'utf-8');
|
||||
|
||||
// Setter should fix the file
|
||||
claudeCliTools.setPromptFormat(testProjectDir, 'yaml');
|
||||
|
||||
// Should now read correctly
|
||||
assert.equal(claudeCliTools.getPromptFormat(testProjectDir), 'yaml');
|
||||
|
||||
// File should be valid JSON
|
||||
const content = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
||||
assert.equal(content.promptFormat, 'yaml');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Edge cases', () => {
|
||||
it('should handle empty string for defaultModel', () => {
|
||||
claudeCliTools.setDefaultModel(testProjectDir, '');
|
||||
const retrieved = claudeCliTools.getDefaultModel(testProjectDir);
|
||||
assert.equal(retrieved, '');
|
||||
});
|
||||
|
||||
it('should handle very long model names', () => {
|
||||
const longModelName = 'a'.repeat(1000);
|
||||
claudeCliTools.setDefaultModel(testProjectDir, longModelName);
|
||||
const retrieved = claudeCliTools.getDefaultModel(testProjectDir);
|
||||
assert.equal(retrieved, longModelName);
|
||||
});
|
||||
|
||||
it('should handle special characters in model names', () => {
|
||||
const specialName = 'model-@#$%^&*()_+{}[]|:;<>?,./~`';
|
||||
claudeCliTools.setDefaultModel(testProjectDir, specialName);
|
||||
const retrieved = claudeCliTools.getDefaultModel(testProjectDir);
|
||||
assert.equal(retrieved, specialName);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user