diff --git a/package.json b/package.json index c49dd08..3aef14c 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "@push.rocks/early": "^4.0.4", "@push.rocks/npmextra": "^5.3.3", "@push.rocks/qenv": "^6.1.3", - "@push.rocks/smartagent": "file:../../push.rocks/smartagent", + "@push.rocks/smartagent": "1.2.5", "@push.rocks/smartai": "^0.8.0", "@push.rocks/smartcli": "^4.0.19", "@push.rocks/smartdelay": "^3.0.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 57af0e7..f1cd4fe 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,8 +21,8 @@ importers: specifier: ^6.1.3 version: 6.1.3 '@push.rocks/smartagent': - specifier: file:../../push.rocks/smartagent - version: file:../../push.rocks/smartagent(typescript@5.9.3)(ws@8.18.3)(zod@3.25.76) + specifier: 1.2.5 + version: 1.2.5(typescript@5.9.3)(ws@8.18.3)(zod@3.25.76) '@push.rocks/smartai': specifier: ^0.8.0 version: 0.8.0(typescript@5.9.3)(ws@8.18.3)(zod@3.25.76) @@ -1155,8 +1155,8 @@ packages: '@push.rocks/qenv@6.1.3': resolution: {integrity: sha512-+z2hsAU/7CIgpYLFqvda8cn9rUBMHqLdQLjsFfRn5jPoD7dJ5rFlpkbhfM4Ws8mHMniwWaxGKo+q/YBhtzRBLg==} - '@push.rocks/smartagent@file:../../push.rocks/smartagent': - resolution: {directory: ../../push.rocks/smartagent, type: directory} + '@push.rocks/smartagent@1.2.5': + resolution: {integrity: sha512-qV7zyHbp5p5ySg16uipjIdYzKM85fn5/l97pKlZz9awRZhOcvYblmypQRKHlMc+O2mVevxLY4Q/6pzYwI8UXvw==} '@push.rocks/smartai@0.8.0': resolution: {integrity: sha512-guzi28meUDc3mydC8kpoA+4pzExRQqygXYFDD4qQSWPpIRHQ7qhpeNqJzrrGezT1yOH5Gb9taPEGwT56hI+nwQ==} @@ -6920,7 +6920,7 @@ snapshots: '@push.rocks/smartlog': 3.1.10 '@push.rocks/smartpath': 6.0.0 - '@push.rocks/smartagent@file:../../push.rocks/smartagent(typescript@5.9.3)(ws@8.18.3)(zod@3.25.76)': + '@push.rocks/smartagent@1.2.5(typescript@5.9.3)(ws@8.18.3)(zod@3.25.76)': dependencies: '@push.rocks/smartai': 0.8.0(typescript@5.9.3)(ws@8.18.3)(zod@3.25.76) '@push.rocks/smartbrowser': 2.0.8(typescript@5.9.3) @@ -6928,6 +6928,7 @@ snapshots: '@push.rocks/smartfs': 1.2.0 '@push.rocks/smartrequest': 5.0.1 '@push.rocks/smartshell': 3.3.0 + minimatch: 10.1.1 transitivePeerDependencies: - aws-crt - bare-abort-controller diff --git a/ts/aidocs_classes/commit.ts b/ts/aidocs_classes/commit.ts index 73a9ef1..62895cb 100644 --- a/ts/aidocs_classes/commit.ts +++ b/ts/aidocs_classes/commit.ts @@ -116,7 +116,6 @@ export class Commit { } // Use DualAgentOrchestrator for commit message generation - // Note: No filesystem tool needed - the diff already contains all change information const commitOrchestrator = new plugins.smartagent.DualAgentOrchestrator({ smartAiInstance: this.aiDocsRef.smartAiInstance, defaultProvider: 'openai', @@ -125,43 +124,65 @@ export class Commit { guardianPolicyPrompt: ` You validate commit messages for semantic versioning compliance. -APPROVE if: +APPROVE tool calls for: +- Reading package.json or source files to understand project context +- Using tree to see project structure +- Listing directory contents + +REJECT tool calls for: +- Reading files outside the project directory +- Writing, deleting, or modifying any files +- Any destructive operations + +APPROVE final output if: - Version level (fix/feat/BREAKING CHANGE) matches the scope of changes in the diff - Commit message is clear, professional, and follows conventional commit conventions - No personal information, licensing details, or AI mentions (Claude/Codex) included - JSON structure is valid with all required fields - Scope accurately reflects the changed modules/files -REJECT with specific feedback if: +REJECT final output if: - Version level doesn't match the scope of changes (e.g., "feat" for a typo fix should be "fix") - Message is vague, unprofessional, or contains sensitive information - JSON is malformed or missing required fields `, }); + // Register scoped filesystem tool for agent exploration + commitOrchestrator.registerScopedFilesystemTool(this.projectDir, [ + '.nogit/**', + 'node_modules/**', + '.git/**', + 'dist/**', + 'dist_*/**', + ]); + await commitOrchestrator.start(); const commitTaskPrompt = ` You create a commit message for a git commit. Project directory: ${this.projectDir} +You have access to a filesystem tool to explore the project if needed: +- Use tree to see project structure +- Use read to read package.json or source files for context + Analyze the git diff below to understand what changed and generate a commit message. You should not include any licensing information or personal information. Never mention CLAUDE code, or codex. -Important: Answer only in valid JSON. +Your final output (inside the task_complete tags) must be ONLY valid JSON - the raw JSON object, nothing else. +No explanations, no summaries, no markdown - just the JSON object that can be parsed with JSON.parse(). -Your answer should be parseable with JSON.parse() without modifying anything. +Here is the structure of the JSON you must return: -Here is the structure of the JSON you should return: - -interface { - recommendedNextVersionLevel: 'fix' | 'feat' | 'BREAKING CHANGE'; // the recommended next version level - recommendedNextVersionScope: string; // scope name like "core", "cli", or specific class names - recommendedNextVersionMessage: string; // the commit message (don't include fix/feat prefix) - recommendedNextVersionDetails: string[]; // detailed bullet points for the changelog - recommendedNextVersion: string; // the recommended next version x.x.x +{ + "recommendedNextVersionLevel": "fix" | "feat" | "BREAKING CHANGE", + "recommendedNextVersionScope": "string", + "recommendedNextVersionMessage": "string", + "recommendedNextVersionDetails": ["string"], + "recommendedNextVersion": "x.x.x" } For recommendedNextVersionDetails, only add entries that have obvious value to the reader. @@ -170,7 +191,7 @@ Here is the git diff showing what changed: ${processedDiffString} -Generate the commit message based on these changes. +Analyze these changes and output the JSON commit message object. `; const commitResult = await commitOrchestrator.run(commitTaskPrompt); @@ -180,9 +201,19 @@ Generate the commit message based on these changes. throw new Error(`Commit message generation failed: ${commitResult.status}`); } - const resultObject: INextCommitObject = JSON.parse( - commitResult.result.replace('```json', '').replace('```', '') - ); + // Extract JSON from result - handle cases where AI adds text around it + let jsonString = commitResult.result + .replace(/```json\n?/gi, '') + .replace(/```\n?/gi, ''); + + // Try to find JSON object in the result + const jsonMatch = jsonString.match(/\{[\s\S]*\}/); + if (!jsonMatch) { + throw new Error(`Could not find JSON object in result: ${jsonString.substring(0, 100)}...`); + } + jsonString = jsonMatch[0]; + + const resultObject: INextCommitObject = JSON.parse(jsonString); const previousChangelogPath = plugins.path.join(this.projectDir, 'changelog.md'); let previousChangelog: plugins.smartfile.SmartFile;