-
Notifications
You must be signed in to change notification settings - Fork 35
chore(reset): remove PR prompt flow #106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Changes from 8 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
e3680c4
chore(reset): remove PR prompt flow
ymkiux a89b22f
feat(plugins): add builtin rule acknowledgement template
ymkiux c519576
feat(plugins): show creator and maintainers
ymkiux d5de2cc
chore(plugins): use github handles for ownership
ymkiux 6abbd58
refactor(plugins): split builtin templates into folders
ymkiux e838719
refactor(plugins): flatten builtin template folders
ymkiux f9b4432
chore(plugins): generate registry from folders
ymkiux c40bdee
chore(plugins): bind ownership to plugin id
ymkiux eec1cf3
chore(templates): bind ownership to template id
ymkiux ec4a171
refactor(templates): centralize ownership map
ymkiux 35669e0
style(usage): cap top paths height
ymkiux 23c855d
fix(plugins): avoid runtime ownership crash
ymkiux 30daad0
style(usage): reduce top paths whitespace
ymkiux 5da3e5d
style(usage): avoid gaps for top paths card
ymkiux File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import { pluginOwnership } from '../ownership.mjs'; | ||
|
|
||
| export function buildBuiltinCommentPolishTemplate(t) { | ||
| const tr = (key, fallback, params = null) => (typeof t === 'function' ? t(key, params) : fallback); | ||
| const line1 = tr('plugins.builtin.commentPolish.line1', '轻微收敛以下代码注释'); | ||
| const timestamp = new Date().toISOString(); | ||
| return { | ||
| id: 'builtin_comment_polish', | ||
| name: tr('plugins.builtin.commentPolish.name', '代码注释润色'), | ||
| description: tr('plugins.builtin.commentPolish.desc', '轻微收敛以下代码注释 {{code}}'), | ||
| template: [ | ||
| line1, | ||
| '', | ||
| '{{code}}' | ||
| ].join('\n'), | ||
| createdAt: timestamp, | ||
| updatedAt: timestamp, | ||
| isBuiltin: true, | ||
| createdBy: pluginOwnership.createdBy, | ||
| maintainers: pluginOwnership.maintainers | ||
| }; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,19 @@ | ||
| export const pluginMeta = { | ||
| import { pluginOwnership } from './ownership.mjs'; | ||
|
|
||
| const baseMeta = { | ||
| id: 'prompt-templates', | ||
| title: 'Prompt Templates', | ||
| description: 'Standardized, template-driven prompts with variables and copy/export helpers.', | ||
| statusLabel: 'standard', | ||
| tone: 'configured' | ||
| }; | ||
|
|
||
| if (pluginOwnership && pluginOwnership.pluginId && pluginOwnership.pluginId !== baseMeta.id) { | ||
| throw new Error(`ownership.mjs pluginId mismatch: expected ${baseMeta.id}, got ${pluginOwnership.pluginId}`); | ||
| } | ||
|
|
||
| export const pluginMeta = { | ||
| ...baseMeta, | ||
| createdBy: pluginOwnership && typeof pluginOwnership.createdBy === 'string' ? pluginOwnership.createdBy : '', | ||
| maintainers: pluginOwnership && Array.isArray(pluginOwnership.maintainers) ? pluginOwnership.maintainers : [] | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| export const pluginOwnership = { | ||
| pluginId: 'prompt-templates', | ||
| createdBy: 'ymkiux', | ||
| maintainers: ['ymkiux'] | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| import { pluginOwnership } from '../ownership.mjs'; | ||
|
|
||
| export function buildBuiltinRuleAckTemplate(t) { | ||
| const tr = (key, fallback, params = null) => (typeof t === 'function' ? t(key, params) : fallback); | ||
| const line1 = tr('plugins.builtin.ruleAck.line1', '请根据【{{rule}}】,收到请回复'); | ||
| const timestamp = new Date().toISOString(); | ||
| return { | ||
| id: 'builtin_rule_ack', | ||
| name: tr('plugins.builtin.ruleAck.name', '规则确认回复'), | ||
| description: tr('plugins.builtin.ruleAck.desc', '请根据【{{rule}}】,收到请回复'), | ||
| template: line1, | ||
| createdAt: timestamp, | ||
| updatedAt: timestamp, | ||
| isBuiltin: true, | ||
| createdBy: pluginOwnership.createdBy, | ||
| maintainers: pluginOwnership.maintainers | ||
| }; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| import assert from 'assert'; | ||
| import fs from 'fs'; | ||
| import path from 'path'; | ||
| import { fileURLToPath, pathToFileURL } from 'url'; | ||
|
|
||
| const __filename = fileURLToPath(import.meta.url); | ||
| const __dirname = path.dirname(__filename); | ||
| const root = path.join(__dirname, '..', '..'); | ||
| const pluginsDir = path.join(root, 'plugins'); | ||
|
|
||
| function listPluginFolders() { | ||
| const entries = fs.readdirSync(pluginsDir, { withFileTypes: true }); | ||
| return entries | ||
| .filter((entry) => entry.isDirectory()) | ||
| .map((entry) => entry.name) | ||
| .filter((name) => !name.startsWith('.')) | ||
| .sort((a, b) => a.localeCompare(b, 'en-US')); | ||
| } | ||
|
|
||
| function isPluginFolder(name) { | ||
| const manifestPath = path.join(pluginsDir, name, 'manifest.mjs'); | ||
| const overviewPath = path.join(pluginsDir, name, 'overview.mjs'); | ||
| return fs.existsSync(manifestPath) && fs.existsSync(overviewPath); | ||
| } | ||
|
|
||
| test('each builtin plugin has ownership file matched to plugin id', async () => { | ||
| const folders = listPluginFolders().filter((name) => isPluginFolder(name)); | ||
| assert.ok(folders.length > 0, 'expected at least one builtin plugin folder'); | ||
|
|
||
| for (const folder of folders) { | ||
| const ownershipPath = path.join(pluginsDir, folder, 'ownership.mjs'); | ||
| assert.ok(fs.existsSync(ownershipPath), `missing ownership.mjs for plugin: ${folder}`); | ||
|
|
||
| const manifestUrl = pathToFileURL(path.join(pluginsDir, folder, 'manifest.mjs')).href; | ||
| const ownershipUrl = pathToFileURL(ownershipPath).href; | ||
| const { pluginMeta } = await import(`${manifestUrl}?t=${Date.now()}`); | ||
| const { pluginOwnership } = await import(`${ownershipUrl}?t=${Date.now()}`); | ||
|
|
||
| assert.ok(pluginMeta && typeof pluginMeta === 'object', `invalid pluginMeta for plugin: ${folder}`); | ||
| assert.strictEqual(pluginMeta.id, folder, `pluginMeta.id must match folder name: ${folder}`); | ||
| assert.ok(pluginOwnership && typeof pluginOwnership === 'object', `invalid pluginOwnership for plugin: ${folder}`); | ||
| assert.strictEqual(pluginOwnership.pluginId, folder, `ownership pluginId must match folder name: ${folder}`); | ||
| assert.ok(typeof pluginOwnership.createdBy === 'string' && pluginOwnership.createdBy.trim(), `ownership createdBy must be a github handle for plugin: ${folder}`); | ||
| assert.ok(Array.isArray(pluginOwnership.maintainers) && pluginOwnership.maintainers.length > 0, `ownership maintainers must be non-empty for plugin: ${folder}`); | ||
| for (const maintainer of pluginOwnership.maintainers) { | ||
| assert.ok(typeof maintainer === 'string' && maintainer.trim(), `ownership maintainer must be a github handle for plugin: ${folder}`); | ||
| } | ||
| } | ||
| }); | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| import assert from 'assert'; | ||
| import fs from 'fs'; | ||
| import path from 'path'; | ||
| import { fileURLToPath } from 'url'; | ||
| import { createRequire } from 'module'; | ||
|
|
||
| const __filename = fileURLToPath(import.meta.url); | ||
| const __dirname = path.dirname(__filename); | ||
| const require = createRequire(import.meta.url); | ||
|
|
||
| const root = path.join(__dirname, '..', '..'); | ||
| const registryPath = path.join(root, 'plugins', 'registry.mjs'); | ||
| const generator = require(path.join(root, 'tools', 'dev', 'generate-plugins-registry.js')); | ||
|
|
||
| test('plugins registry matches generator output', () => { | ||
| const actual = fs.readFileSync(registryPath, 'utf8').replace(/^\uFEFF/u, ''); | ||
| const expected = String(generator.generatePluginsRegistrySource() || '').replace(/^\uFEFF/u, ''); | ||
| assert.strictEqual(actual, expected); | ||
| }); | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| #!/usr/bin/env node | ||
| const fs = require('fs'); | ||
| const path = require('path'); | ||
|
|
||
| const root = path.resolve(__dirname, '..', '..'); | ||
| const pluginsDir = path.join(root, 'plugins'); | ||
| const registryPath = path.join(pluginsDir, 'registry.mjs'); | ||
|
|
||
| function toCamelCase(value) { | ||
| const raw = String(value || '').trim(); | ||
| if (!raw) return ''; | ||
| return raw | ||
| .split(/[^a-zA-Z0-9]+/g) | ||
| .filter(Boolean) | ||
| .map((part, index) => { | ||
| const head = part.slice(0, 1); | ||
| const tail = part.slice(1); | ||
| if (index === 0) return head.toLowerCase() + tail; | ||
| return head.toUpperCase() + tail; | ||
| }) | ||
| .join(''); | ||
| } | ||
|
|
||
| function toPascalCase(value) { | ||
| const camel = toCamelCase(value); | ||
| if (!camel) return ''; | ||
| return camel.slice(0, 1).toUpperCase() + camel.slice(1); | ||
| } | ||
|
|
||
| function listPluginFolders() { | ||
| const entries = fs.readdirSync(pluginsDir, { withFileTypes: true }); | ||
| return entries | ||
| .filter((entry) => entry.isDirectory()) | ||
| .map((entry) => entry.name) | ||
| .filter((name) => !name.startsWith('.')) | ||
| .sort((a, b) => a.localeCompare(b, 'en-US')); | ||
| } | ||
|
|
||
| function isPluginFolder(name) { | ||
| const manifestPath = path.join(pluginsDir, name, 'manifest.mjs'); | ||
| const overviewPath = path.join(pluginsDir, name, 'overview.mjs'); | ||
| return fs.existsSync(manifestPath) && fs.existsSync(overviewPath); | ||
| } | ||
|
|
||
| function generatePluginsRegistrySource() { | ||
| const folders = listPluginFolders().filter((name) => isPluginFolder(name)); | ||
| const imports = []; | ||
| const entries = []; | ||
| for (const folder of folders) { | ||
| const camel = toCamelCase(folder); | ||
| const pascal = toPascalCase(folder); | ||
| const metaName = `${camel}Meta`; | ||
| const loadName = `load${pascal}Overview`; | ||
| imports.push(`import { pluginMeta as ${metaName} } from './${folder}/manifest.mjs';`); | ||
| imports.push(`import { ${loadName} } from './${folder}/overview.mjs';`); | ||
| entries.push(` { id: ${metaName}.id, meta: ${metaName}, loadOverview: ${loadName} }`); | ||
| } | ||
| const lines = [ | ||
| ...imports, | ||
| '', | ||
| 'export const pluginsRegistry = [', | ||
| ...entries.map((line, index) => (index < entries.length - 1 ? `${line},` : line)), | ||
| '];', | ||
| '', | ||
| 'export function getFirstPluginId() {', | ||
| " return pluginsRegistry.length ? pluginsRegistry[0].id : '';", | ||
| '}', | ||
| '', | ||
| 'export function getPluginEntry(id) {', | ||
| " const key = typeof id === 'string' ? id.trim() : '';", | ||
| ' if (!key) return null;', | ||
| ' return pluginsRegistry.find((item) => item && item.id === key) || null;', | ||
| '}', | ||
| '' | ||
| ]; | ||
| return lines.join('\n'); | ||
| } | ||
|
|
||
| function writePluginsRegistry() { | ||
| const next = generatePluginsRegistrySource(); | ||
| fs.writeFileSync(registryPath, next, 'utf8'); | ||
| return next; | ||
| } | ||
|
|
||
| function main() { | ||
| writePluginsRegistry(); | ||
| } | ||
|
|
||
| if (require.main === module) { | ||
| main(); | ||
| } | ||
|
|
||
| module.exports = { | ||
| generatePluginsRegistrySource, | ||
| writePluginsRegistry | ||
| }; | ||
|
|
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: SakuraByteCore/codexmate
Length of output: 2204
🏁 Script executed:
Repository: SakuraByteCore/codexmate
Length of output: 5036
Add these contract test files to the test runner to ensure they are executed.
The test runner (tests/unit/run.mjs) correctly globalizes
teston line 8, so the original concern about missing imports is resolved. However,plugins-registry-contract.test.mjsandplugins-ownership-contract.test.mjsare not imported in run.mjs at all—they exist but are being silently skipped, which is the exact risk flagged. Add them to the import list in run.mjs to ensure these contract checks are actually executed.🤖 Prompt for AI Agents