Skip to content

Commit d03efa9

Browse files
committed
Merge branch 'main' into HEAD
2 parents 52b2a9b + 8af8ff9 commit d03efa9

File tree

13 files changed

+214
-67
lines changed

13 files changed

+214
-67
lines changed

.github/workflows/issue-comment.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,11 @@ jobs:
5454
# Auth GitHub CLI with the token
5555
- name: Configure GitHub CLI
5656
run: |
57-
# First try with GITHUB_TOKEN
58-
echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token
57+
echo "${{ secrets.GH_PAT }}" | gh auth login --with-token
5958
# Verify auth status
6059
gh auth status
6160
6261
- env:
63-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
6462
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
6563
run: |
6664
echo "Running MyCoder for issue #${{ github.event.issue.number }} with prompt: ${{ steps.extract-prompt.outputs.prompt }}"

packages/agent/CHANGELOG.md

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
# mycoder-agent-v1.0.0 (2025-03-11)
22

3-
43
### Bug Fixes
54

6-
* **monorepo:** implement semantic-release-monorepo for proper versioning of sub-packages ([96c6284](https://github.com/drivecore/mycoder/commit/96c62848fbc3a4c1c591f3fd6202486e6461c4f2))
7-
* only consider response empty if no text AND no tool calls ([#127](https://github.com/drivecore/mycoder/issues/127)) ([af20ec5](https://github.com/drivecore/mycoder/commit/af20ec54468afed49632306fe553b307ab3c4ba5))
8-
* Replace shell commands with Node.js APIs for cross-platform compatibility ([07b4c24](https://github.com/drivecore/mycoder/commit/07b4c24fa17d19c468a76404a367f6afc0005517))
9-
* token caching ([5972e59](https://github.com/drivecore/mycoder/commit/5972e59ab572040e564d1756ab8a5625215e14dc))
10-
* use maxTokens in generateTextProps ([bfb9da9](https://github.com/drivecore/mycoder/commit/bfb9da9804d61840344e93cc5bea809e8e16f2ec))
11-
5+
- **monorepo:** implement semantic-release-monorepo for proper versioning of sub-packages ([96c6284](https://github.com/drivecore/mycoder/commit/96c62848fbc3a4c1c591f3fd6202486e6461c4f2))
6+
- only consider response empty if no text AND no tool calls ([#127](https://github.com/drivecore/mycoder/issues/127)) ([af20ec5](https://github.com/drivecore/mycoder/commit/af20ec54468afed49632306fe553b307ab3c4ba5))
7+
- Replace shell commands with Node.js APIs for cross-platform compatibility ([07b4c24](https://github.com/drivecore/mycoder/commit/07b4c24fa17d19c468a76404a367f6afc0005517))
8+
- token caching ([5972e59](https://github.com/drivecore/mycoder/commit/5972e59ab572040e564d1756ab8a5625215e14dc))
9+
- use maxTokens in generateTextProps ([bfb9da9](https://github.com/drivecore/mycoder/commit/bfb9da9804d61840344e93cc5bea809e8e16f2ec))
1210

1311
### Features
1412

15-
* add back token tracking, system prompt caching. ([ddc04ab](https://github.com/drivecore/mycoder/commit/ddc04ab0778eb2f571897e825c8d8ba17651db09))
16-
* add showStdIn and showStdout options to shellMessage and shellStart ([aed1b9f](https://github.com/drivecore/mycoder/commit/aed1b9f6ba489da19f2170c136861a7c80ad6e33)), closes [#167](https://github.com/drivecore/mycoder/issues/167)
17-
* add token caching. issue 145 ([d78723b](https://github.com/drivecore/mycoder/commit/d78723bb6d0514110088caf7009e196e3f79769e))
18-
* remove modelProvider and modelName - instant decrepation ([59834dc](https://github.com/drivecore/mycoder/commit/59834dcf932051a5c75624bd6f6ab12254f43769))
13+
- add back token tracking, system prompt caching. ([ddc04ab](https://github.com/drivecore/mycoder/commit/ddc04ab0778eb2f571897e825c8d8ba17651db09))
14+
- add showStdIn and showStdout options to shellMessage and shellStart ([aed1b9f](https://github.com/drivecore/mycoder/commit/aed1b9f6ba489da19f2170c136861a7c80ad6e33)), closes [#167](https://github.com/drivecore/mycoder/issues/167)
15+
- add token caching. issue 145 ([d78723b](https://github.com/drivecore/mycoder/commit/d78723bb6d0514110088caf7009e196e3f79769e))
16+
- remove modelProvider and modelName - instant decrepation ([59834dc](https://github.com/drivecore/mycoder/commit/59834dcf932051a5c75624bd6f6ab12254f43769))
1917

2018
# mycoder-agent
2119

packages/agent/src/tools/browser/BrowserManager.ts

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ export class BrowserManager {
1515
defaultTimeout: 30000,
1616
};
1717

18+
constructor() {
19+
// Store a reference to the instance globally for cleanup
20+
// This allows the CLI to access the instance for cleanup
21+
(globalThis as any).__BROWSER_MANAGER__ = this;
22+
23+
// Set up cleanup handlers for graceful shutdown
24+
this.setupGlobalCleanup();
25+
}
26+
1827
async createSession(config?: BrowserConfig): Promise<BrowserSession> {
1928
try {
2029
const sessionConfig = { ...this.defaultConfig, ...config };
@@ -80,14 +89,46 @@ export class BrowserManager {
8089
this.sessions.delete(session.id);
8190
});
8291

83-
// Handle process exit
92+
// No need to add individual process handlers for each session
93+
// We'll handle all sessions in the global cleanup
94+
}
95+
96+
/**
97+
* Sets up global cleanup handlers for all browser sessions
98+
*/
99+
private setupGlobalCleanup(): void {
100+
// Use beforeExit for async cleanup
101+
process.on('beforeExit', () => {
102+
this.closeAllSessions().catch((err) => {
103+
console.error('Error closing browser sessions:', err);
104+
});
105+
});
106+
107+
// Use exit for synchronous cleanup (as a fallback)
84108
process.on('exit', () => {
85-
this.closeSession(session.id).catch(() => {});
109+
// Can only do synchronous operations here
110+
for (const session of this.sessions.values()) {
111+
try {
112+
// Attempt synchronous close - may not fully work
113+
session.browser.close();
114+
// eslint-disable-next-line unused-imports/no-unused-vars
115+
} catch (e) {
116+
// Ignore errors during exit
117+
}
118+
}
86119
});
87120

88-
// Handle unexpected errors
89-
process.on('uncaughtException', () => {
90-
this.closeSession(session.id).catch(() => {});
121+
// Handle SIGINT (Ctrl+C)
122+
process.on('SIGINT', () => {
123+
// eslint-disable-next-line promise/catch-or-return
124+
this.closeAllSessions()
125+
.catch(() => {
126+
return false;
127+
})
128+
.finally(() => {
129+
// Give a moment for cleanup to complete
130+
setTimeout(() => process.exit(0), 500);
131+
});
91132
});
92133
}
93134

packages/agent/src/tools/system/shellStart.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ type ProcessState = {
2525
};
2626

2727
// Global map to store process state
28+
// This is exported so it can be accessed for cleanup
2829
export const processStates: Map<string, ProcessState> = new Map();
2930

3031
const parameterSchema = z.object({

packages/cli/CHANGELOG.md

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
# mycoder-v1.0.0 (2025-03-11)
22

3-
43
### Bug Fixes
54

6-
* add deepmerge to cli package.json ([ab66377](https://github.com/drivecore/mycoder/commit/ab66377342c9f23fa874d2776e73d365141e8801))
7-
* don't save consent when using --userWarning=false ([41cf69d](https://github.com/drivecore/mycoder/commit/41cf69dee22acc31cd0f2aa9f80e36cd867fb20b))
8-
* **monorepo:** implement semantic-release-monorepo for proper versioning of sub-packages ([96c6284](https://github.com/drivecore/mycoder/commit/96c62848fbc3a4c1c591f3fd6202486e6461c4f2))
9-
* update hierarchical configuration system to fix failing tests ([93d949c](https://github.com/drivecore/mycoder/commit/93d949c03b7ebe96bad36713f6476c38d2a35224))
10-
5+
- add deepmerge to cli package.json ([ab66377](https://github.com/drivecore/mycoder/commit/ab66377342c9f23fa874d2776e73d365141e8801))
6+
- don't save consent when using --userWarning=false ([41cf69d](https://github.com/drivecore/mycoder/commit/41cf69dee22acc31cd0f2aa9f80e36cd867fb20b))
7+
- **monorepo:** implement semantic-release-monorepo for proper versioning of sub-packages ([96c6284](https://github.com/drivecore/mycoder/commit/96c62848fbc3a4c1c591f3fd6202486e6461c4f2))
8+
- update hierarchical configuration system to fix failing tests ([93d949c](https://github.com/drivecore/mycoder/commit/93d949c03b7ebe96bad36713f6476c38d2a35224))
119

1210
### Features
1311

14-
* add --githubMode and --userPrompt as boolean CLI options that override config settings ([0390f94](https://github.com/drivecore/mycoder/commit/0390f94651e40de93a8cb9486a056a0b9cb2e165))
15-
* add CLI options for automated usage scenarios ([00419bc](https://github.com/drivecore/mycoder/commit/00419bc3e060db6d0c18fc72e2d7b6957791c875))
16-
* add maxTokens and temperature config options to CLI ([b461d3b](https://github.com/drivecore/mycoder/commit/b461d3b71b686d7679ecac62c0c66cc5a1df8fec)), closes [#118](https://github.com/drivecore/mycoder/issues/118)
17-
* implement hierarchical configuration system ([84d73d1](https://github.com/drivecore/mycoder/commit/84d73d1e6324670890a203f455fe257aeb6ed07a)), closes [#153](https://github.com/drivecore/mycoder/issues/153)
18-
* remove modelProvider and modelName - instant decrepation ([59834dc](https://github.com/drivecore/mycoder/commit/59834dcf932051a5c75624bd6f6ab12254f43769))
12+
- add --githubMode and --userPrompt as boolean CLI options that override config settings ([0390f94](https://github.com/drivecore/mycoder/commit/0390f94651e40de93a8cb9486a056a0b9cb2e165))
13+
- add CLI options for automated usage scenarios ([00419bc](https://github.com/drivecore/mycoder/commit/00419bc3e060db6d0c18fc72e2d7b6957791c875))
14+
- add maxTokens and temperature config options to CLI ([b461d3b](https://github.com/drivecore/mycoder/commit/b461d3b71b686d7679ecac62c0c66cc5a1df8fec)), closes [#118](https://github.com/drivecore/mycoder/issues/118)
15+
- implement hierarchical configuration system ([84d73d1](https://github.com/drivecore/mycoder/commit/84d73d1e6324670890a203f455fe257aeb6ed07a)), closes [#153](https://github.com/drivecore/mycoder/issues/153)
16+
- remove modelProvider and modelName - instant decrepation ([59834dc](https://github.com/drivecore/mycoder/commit/59834dcf932051a5c75624bd6f6ab12254f43769))
1917

2018
# mycoder
2119

packages/cli/COMMIT_CONVENTION.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,3 @@ Commit messages are used to:
5151
1. Automatically determine the next version number
5252
2. Generate changelog entries
5353
3. Create GitHub releases
54-

packages/cli/src/commands/config.ts

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import * as path from 'path';
2+
13
import chalk from 'chalk';
24
import { Logger } from 'mycoder-agent';
35

@@ -8,6 +10,7 @@ import {
810
updateConfig,
911
getConfigAtLevel,
1012
clearConfigAtLevel,
13+
clearConfigKey,
1114
ConfigLevel,
1215
} from '../settings/config.js';
1316
import { nameToLogIndex } from '../utils/nameToLogIndex.js';
@@ -18,7 +21,9 @@ export interface ConfigOptions extends SharedOptions {
1821
command: 'get' | 'set' | 'list' | 'clear';
1922
key?: string;
2023
value?: string;
21-
all?: boolean;
24+
all: boolean; // Has default value in builder, so it's always defined
25+
global: boolean; // Has default value in builder, so it's always defined
26+
verbose: boolean; // Has default value in builder, so it's always defined
2227
}
2328

2429
export const command: CommandModule<SharedOptions, ConfigOptions> = {
@@ -45,6 +50,18 @@ export const command: CommandModule<SharedOptions, ConfigOptions> = {
4550
type: 'boolean',
4651
default: false,
4752
})
53+
.option('global', {
54+
alias: 'g',
55+
describe: 'Use global configuration instead of project-level',
56+
type: 'boolean',
57+
default: false,
58+
})
59+
.option('verbose', {
60+
alias: 'v',
61+
describe: 'Show detailed information including config file paths',
62+
type: 'boolean',
63+
default: false,
64+
})
4865
.example('$0 config list', 'List all configuration values')
4966
.example(
5067
'$0 config get githubMode',
@@ -117,15 +134,15 @@ export const command: CommandModule<SharedOptions, ConfigOptions> = {
117134
// Import directly to avoid circular dependency
118135
const { getSettingsDir } = await import('../settings/settings.js');
119136
const { getProjectConfigFile } = await import('../settings/config.js');
120-
137+
121138
const globalConfigFile = path.join(getSettingsDir(), 'config.json');
122139
const projectConfigFile = getProjectConfigFile();
123-
140+
124141
logger.info('Current configuration:');
125142
logger.info(`Global config file: ${globalConfigFile}`);
126143
logger.info(`Project config file: ${projectConfigFile}`);
127144
logger.info('');
128-
145+
129146
const defaultConfig = getDefaultConfig();
130147

131148
// Get all valid config keys
@@ -287,15 +304,8 @@ export const command: CommandModule<SharedOptions, ConfigOptions> = {
287304
return;
288305
}
289306

290-
// Get the current config, create a new object without the specified key
291-
const currentConfig = getConfig();
292-
const { [argv.key]: _, ...newConfig } = currentConfig as Record<
293-
string,
294-
any
295-
>;
296-
297-
// Update the config file with the new object
298-
updateConfig(newConfig);
307+
// Clear the specified key from the configuration at the current level
308+
clearConfigKey(argv.key, configLevel);
299309

300310
// Get the default value that will now be used
301311
const defaultValue =
@@ -308,13 +318,23 @@ export const command: CommandModule<SharedOptions, ConfigOptions> = {
308318
// Determine where the new value is coming from
309319
const isDefaultAfterClear =
310320
JSON.stringify(newValue) === JSON.stringify(defaultValue);
321+
322+
// Get the actual config values at each level
323+
const globalConfig = getConfigAtLevel(ConfigLevel.GLOBAL);
324+
const projectConfig = getConfigAtLevel(ConfigLevel.PROJECT);
325+
326+
// Check if key exists AND has a non-default value in each level
311327
const afterClearInGlobal =
312328
!isDefaultAfterClear &&
313-
argv.key in getConfigAtLevel(ConfigLevel.GLOBAL);
329+
argv.key in globalConfig &&
330+
JSON.stringify(globalConfig[argv.key]) !== JSON.stringify(defaultValue);
331+
314332
const afterClearInProject =
315333
!isDefaultAfterClear &&
316334
!afterClearInGlobal &&
317-
argv.key in getConfigAtLevel(ConfigLevel.PROJECT);
335+
argv.key in projectConfig &&
336+
JSON.stringify(projectConfig[argv.key]) !==
337+
JSON.stringify(defaultValue);
318338

319339
let sourceDisplay = '';
320340
if (isDefaultAfterClear) {

packages/cli/src/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { command as toolsCommand } from './commands/tools.js';
1313
import { sharedOptions } from './options.js';
1414
import { initSentry, captureException } from './sentry/index.js';
1515
import { getConfig } from './settings/config.js';
16+
import { cleanupResources, setupForceExit } from './utils/cleanup.js';
1617
import { enableProfiling, mark, reportTimings } from './utils/performance.js';
1718

1819
mark('After imports');
@@ -82,4 +83,11 @@ await main()
8283
.finally(async () => {
8384
// Report timings if profiling is enabled
8485
await reportTimings();
86+
87+
// Clean up all resources before exit
88+
await cleanupResources();
89+
90+
// Setup a force exit as a failsafe
91+
// This ensures the process will exit even if there are lingering handles
92+
setupForceExit(5000);
8593
});

packages/cli/src/settings/config.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const globalConfigFile = path.join(getSettingsDir(), 'config.json');
2323
// Export for testing
2424
export const getProjectConfigFile = (): string => {
2525
const projectDir = getProjectSettingsDir();
26-
26+
2727
// Ensure the project directory exists
2828
if (projectDir && !fs.existsSync(projectDir)) {
2929
try {
@@ -33,7 +33,7 @@ export const getProjectConfigFile = (): string => {
3333
return '';
3434
}
3535
}
36-
36+
3737
return projectDir ? path.join(projectDir, 'config.json') : '';
3838
};
3939

@@ -286,9 +286,17 @@ export const clearConfigKey = (
286286
}
287287

288288
// Create a new config without the specified key
289-
const { [key]: _, ...newConfig } = currentLevelConfig as Record<string, any>;
289+
const { [key]: removedValue, ...newConfig } = currentLevelConfig as Record<
290+
string,
291+
any
292+
>;
293+
console.log(`Removed value for key ${key}:`, removedValue);
290294

291295
// Write the updated config back to the file
296+
console.log(`Clearing key ${key} from ${targetFile}`);
297+
console.log(`Original config:`, JSON.stringify(currentLevelConfig, null, 2));
298+
console.log(`New config without key:`, JSON.stringify(newConfig, null, 2));
299+
292300
fs.writeFileSync(targetFile, JSON.stringify(newConfig, null, 2));
293301

294302
// Return the new merged configuration

packages/cli/src/settings/settings.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export const getProjectSettingsDir = (): string => {
3434

3535
// If we're creating a new project config, use the current directory
3636
const projectDir = path.join(process.cwd(), '.mycoder');
37-
37+
3838
// Ensure directory exists when it's requested
3939
if (!fs.existsSync(projectDir)) {
4040
try {
@@ -45,7 +45,7 @@ export const getProjectSettingsDir = (): string => {
4545
// as other code will handle the error when trying to use it
4646
}
4747
}
48-
48+
4949
return projectDir;
5050
};
5151

0 commit comments

Comments
 (0)