Collections Improvement with Tasks Collection POC (#270)
* add yaml block support * Add usage Section to Collections * new edge ai tasks collection with usage example from PR https://github.com/github/awesome-copilot/pull/159 * Update collections/edge-ai-tasks.collection.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update collections/edge-ai-tasks.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update collections/edge-ai-tasks.collection.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update collections/edge-ai-tasks.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fixing some bugs in the update script --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Aaron Powell <me@aaron-powell.com>
This commit is contained in:
parent
ccee5c44eb
commit
afc0705b11
@ -57,6 +57,10 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Type of the item",
|
"description": "Type of the item",
|
||||||
"enum": ["prompt", "instruction", "chat-mode"]
|
"enum": ["prompt", "instruction", "chat-mode"]
|
||||||
|
},
|
||||||
|
"usage": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Optional usage context for the item"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -25,5 +25,6 @@ Curated collections of related prompts, instructions, and chat modes organized a
|
|||||||
| [Power Apps Code Apps Development](collections/power-apps-code-apps.md) | Complete toolkit for Power Apps Code Apps development including project scaffolding, development standards, and expert guidance for building code-first applications with Power Platform integration. | 3 items | power-apps, power-platform, typescript, react, code-apps, dataverse, connectors |
|
| [Power Apps Code Apps Development](collections/power-apps-code-apps.md) | Complete toolkit for Power Apps Code Apps development including project scaffolding, development standards, and expert guidance for building code-first applications with Power Platform integration. | 3 items | power-apps, power-platform, typescript, react, code-apps, dataverse, connectors |
|
||||||
| [Project Planning & Management](collections/project-planning.md) | Tools and guidance for software project planning, feature breakdown, epic management, implementation planning, and task organization for development teams. | 17 items | planning, project-management, epic, feature, implementation, task, architecture, technical-spike |
|
| [Project Planning & Management](collections/project-planning.md) | Tools and guidance for software project planning, feature breakdown, epic management, implementation planning, and task organization for development teams. | 17 items | planning, project-management, epic, feature, implementation, task, architecture, technical-spike |
|
||||||
| [Security & Code Quality](collections/security-best-practices.md) | Security frameworks, accessibility guidelines, performance optimization, and code quality best practices for building secure, maintainable, and high-performance applications. | 6 items | security, accessibility, performance, code-quality, owasp, a11y, optimization, best-practices |
|
| [Security & Code Quality](collections/security-best-practices.md) | Security frameworks, accessibility guidelines, performance optimization, and code quality best practices for building secure, maintainable, and high-performance applications. | 6 items | security, accessibility, performance, code-quality, owasp, a11y, optimization, best-practices |
|
||||||
|
| [Tasks by microsoft/edge-ai](collections/edge-ai-tasks.md) | Task Researcher and Task Planner for intermediate to expert users and large codebases - Brought to you by microsoft/edge-ai | 3 items | architecture, planning, research, tasks, implementation |
|
||||||
| [Technical Spike](collections/technical-spike.md) | Tools for creation, management and research of technical spikes to reduce unknowns and assumptions before proceeding to specification and implementation of solutions. | 2 items | technical-spike, assumption-testing, validation, research |
|
| [Technical Spike](collections/technical-spike.md) | Tools for creation, management and research of technical spikes to reduce unknowns and assumptions before proceeding to specification and implementation of solutions. | 2 items | technical-spike, assumption-testing, validation, research |
|
||||||
| [Testing & Test Automation](collections/testing-automation.md) | Comprehensive collection for writing tests, test automation, and test-driven development including unit tests, integration tests, and end-to-end testing strategies. | 11 items | testing, tdd, automation, unit-tests, integration, playwright, jest, nunit |
|
| [Testing & Test Automation](collections/testing-automation.md) | Comprehensive collection for writing tests, test automation, and test-driven development including unit tests, integration tests, and end-to-end testing strategies. | 11 items | testing, tdd, automation, unit-tests, integration, playwright, jest, nunit |
|
||||||
|
|||||||
90
collections/edge-ai-tasks.collection.yml
Normal file
90
collections/edge-ai-tasks.collection.yml
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
id: edge-ai-tasks
|
||||||
|
name: Tasks by microsoft/edge-ai
|
||||||
|
description: Task Researcher and Task Planner for intermediate to expert users and large codebases - Brought to you by microsoft/edge-ai
|
||||||
|
tags: [architecture, planning, research, tasks, implementation]
|
||||||
|
items:
|
||||||
|
# Planning Chat Modes
|
||||||
|
- path: chatmodes/task-researcher.chatmode.md
|
||||||
|
kind: chat-mode
|
||||||
|
usage: |
|
||||||
|
Now you can iterate on research for your tasks!
|
||||||
|
|
||||||
|
```markdown, research.prompt.md
|
||||||
|
---
|
||||||
|
mode: task-researcher
|
||||||
|
title: Research microsoft fabric realtime intelligence terraform support
|
||||||
|
---
|
||||||
|
Review the microsoft documentation for fabric realtime intelligence
|
||||||
|
and come up with ideas on how to implement this support into our terraform components.
|
||||||
|
```
|
||||||
|
|
||||||
|
Research is dumped out into a .copilot-tracking/research/*-research.md file and will include discoveries for GHCP along with examples and schema that will be useful during implementation.
|
||||||
|
|
||||||
|
Also, task-researcher will provide additional ideas for implementation which you can work with GitHub Copilot on selecting the right one to focus on.
|
||||||
|
|
||||||
|
- path: chatmodes/task-planner.chatmode.md
|
||||||
|
kind: chat-mode
|
||||||
|
usage: |
|
||||||
|
Also, task-researcher will provide additional ideas for implementation which you can work with GitHub Copilot on selecting the right one to focus on.
|
||||||
|
|
||||||
|
```markdown, task-plan.prompt.md
|
||||||
|
---
|
||||||
|
mode: task-planner
|
||||||
|
title: Plan microsoft fabric realtime intelligence terraform support
|
||||||
|
---
|
||||||
|
#file: .copilot-tracking/research/*-fabric-rti-blueprint-modification-research.md
|
||||||
|
Build a plan to support adding fabric rti to this project
|
||||||
|
```
|
||||||
|
|
||||||
|
`task-planner` will help you create a plan for implementing your task(s). It will use your fully researched ideas or build new research if not already provided.
|
||||||
|
|
||||||
|
`task-planner` will produce three (3) files that will be used by `task-implementation.instructions.md`.
|
||||||
|
|
||||||
|
* `.copilot-tracking/plan/*-plan.instructions.md`
|
||||||
|
|
||||||
|
* A newly generated instructions file that has the plan as a checklist of Phases and Tasks.
|
||||||
|
* `.copilot-tracking/details/*-details.md`
|
||||||
|
|
||||||
|
* The details for the implementation, the plan file refers to this file for specific details (important if you have a big plan).
|
||||||
|
* `.copilot-tracking/prompts/implement-*.prompt.md`
|
||||||
|
|
||||||
|
* A newly generated prompt file that will create a `.copilot-tracking/changes/*-changes.md` file and proceed to implement the changes.
|
||||||
|
|
||||||
|
Continue to use `task-planner` to iterate on the plan until you have exactly what you want done to your codebase.
|
||||||
|
|
||||||
|
# Planning Instructions
|
||||||
|
- path: instructions/task-implementation.instructions.md
|
||||||
|
kind: instruction
|
||||||
|
usage: |
|
||||||
|
Continue to use `task-planner` to iterate on the plan until you have exactly what you want done to your codebase.
|
||||||
|
|
||||||
|
When you are ready to implement the plan, **create a new chat** and switch to `Agent` mode then fire off the newly generated prompt.
|
||||||
|
|
||||||
|
```markdown, implement-fabric-rti-changes.prompt.md
|
||||||
|
---
|
||||||
|
mode: agent
|
||||||
|
title: Implement microsoft fabric realtime intelligence terraform support
|
||||||
|
---
|
||||||
|
/implement-fabric-rti-blueprint-modification phaseStop=true
|
||||||
|
```
|
||||||
|
|
||||||
|
This prompt has the added benefit of attaching the plan as instructions, which helps with keeping the plan in context throughout the whole conversation.
|
||||||
|
|
||||||
|
**Expert Warning** ->>Use `phaseStop=false` to have Copilot implement the whole plan without stopping. Additionally, you can use `taskStop=true` to have Copilot stop after every Task implementation for finer detail control.
|
||||||
|
|
||||||
|
To use these generated instructions and prompts, you'll need to update your `settings.json` accordingly:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"chat.instructionsFilesLocations": {
|
||||||
|
// Existing instructions folders...
|
||||||
|
".copilot-tracking/plans": true
|
||||||
|
},
|
||||||
|
"chat.promptFilesLocations": {
|
||||||
|
// Existing prompts folders...
|
||||||
|
".copilot-tracking/prompts": true
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
display:
|
||||||
|
ordering: alpha # or "manual" to preserve the order above
|
||||||
|
show_badge: false # set to true to show collection badge on items
|
||||||
100
collections/edge-ai-tasks.md
Normal file
100
collections/edge-ai-tasks.md
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
# Tasks by microsoft/edge-ai
|
||||||
|
|
||||||
|
Task Researcher and Task Planner for intermediate to expert users and large codebases - Brought to you by microsoft/edge-ai
|
||||||
|
|
||||||
|
**Tags:** architecture, planning, research, tasks, implementation
|
||||||
|
|
||||||
|
## Items in this Collection
|
||||||
|
|
||||||
|
| Title | Type | Description |
|
||||||
|
| ----- | ---- | ----------- |
|
||||||
|
| [Task Researcher Instructions](../chatmodes/task-researcher.chatmode.md)<br />[](https://aka.ms/awesome-copilot/install/chatmode?url=vscode%3Achat-mode%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fchatmodes%2Ftask-researcher.chatmode.md)<br />[](https://aka.ms/awesome-copilot/install/chatmode?url=vscode-insiders%3Achat-mode%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fchatmodes%2Ftask-researcher.chatmode.md) | Chat Mode | Task research specialist for comprehensive project analysis - Brought to you by microsoft/edge-ai [see usage](#task-researcher-instructions) |
|
||||||
|
| [Task Planner Instructions](../chatmodes/task-planner.chatmode.md)<br />[](https://aka.ms/awesome-copilot/install/chatmode?url=vscode%3Achat-mode%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fchatmodes%2Ftask-planner.chatmode.md)<br />[](https://aka.ms/awesome-copilot/install/chatmode?url=vscode-insiders%3Achat-mode%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Fchatmodes%2Ftask-planner.chatmode.md) | Chat Mode | Task planner for creating actionable implementation plans - Brought to you by microsoft/edge-ai [see usage](#task-planner-instructions) |
|
||||||
|
| [Task Plan Implementation Instructions](../instructions/task-implementation.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Ftask-implementation.instructions.md)<br />[](https://aka.ms/awesome-copilot/install/instructions?url=vscode-insiders%3Achat-instructions%2Finstall%3Furl%3Dhttps%3A%2F%2Fraw.githubusercontent.com%2Fgithub%2Fawesome-copilot%2Fmain%2Finstructions%2Ftask-implementation.instructions.md) | Instruction | Instructions for implementing task plans with progressive tracking and change record - Brought to you by microsoft/edge-ai [see usage](#task-plan-implementation-instructions) |
|
||||||
|
|
||||||
|
## Collection Usage
|
||||||
|
|
||||||
|
### Task Researcher Instructions
|
||||||
|
|
||||||
|
Now you can iterate on research for your tasks!
|
||||||
|
|
||||||
|
```markdown, research.prompt.md
|
||||||
|
---
|
||||||
|
mode: task-researcher
|
||||||
|
title: Research microsoft fabric realtime intelligence terraform support
|
||||||
|
---
|
||||||
|
Review the microsoft documentation for fabric realtime intelligence
|
||||||
|
and come up with ideas on how to implement this support into our terraform components.
|
||||||
|
```
|
||||||
|
|
||||||
|
Research is dumped out into a .copilot-tracking/research/*-research.md file and will include discoveries for GHCP along with examples and schema that will be useful during implementation.
|
||||||
|
|
||||||
|
Also, task-researcher will provide additional ideas for implementation which you can work with GitHub Copilot on selecting the right one to focus on.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task Planner Instructions
|
||||||
|
|
||||||
|
Also, task-researcher will provide additional ideas for implementation which you can work with GitHub Copilot on selecting the right one to focus on.
|
||||||
|
|
||||||
|
```markdown, task-plan.prompt.md
|
||||||
|
---
|
||||||
|
mode: task-planner
|
||||||
|
title: Plan microsoft fabric realtime intelligence terraform support
|
||||||
|
---
|
||||||
|
#file: .copilot-tracking/research/*-fabric-rti-blueprint-modification-research.md
|
||||||
|
Build a plan to support adding fabric rti to this project
|
||||||
|
```
|
||||||
|
|
||||||
|
`task-planner` will help you create a plan for implementing your task(s). It will use your fully researched ideas or build new research if not already provided.
|
||||||
|
|
||||||
|
`task-planner` will produce three (3) files that will be used by `task-implementation.instructions.md`.
|
||||||
|
|
||||||
|
* `.copilot-tracking/plan/*-plan.instructions.md`
|
||||||
|
|
||||||
|
* A newly generated instructions file that has the plan as a checklist of Phases and Tasks.
|
||||||
|
* `.copilot-tracking/details/*-details.md`
|
||||||
|
|
||||||
|
* The details for the implementation, the plan file refers to this file for specific details (important if you have a big plan).
|
||||||
|
* `.copilot-tracking/prompts/implement-*.prompt.md`
|
||||||
|
|
||||||
|
* A newly generated prompt file that will create a `.copilot-tracking/changes/*-changes.md` file and proceed to implement the changes.
|
||||||
|
|
||||||
|
Continue to use `task-planner` to iterate on the plan until you have exactly what you want done to your codebase.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task Plan Implementation Instructions
|
||||||
|
|
||||||
|
Continue to use `task-planner` to iterate on the plan until you have exactly what you want done to your codebase.
|
||||||
|
|
||||||
|
When you are ready to implement the plan, **create a new chat** and switch to `Agent` mode then fire off the newly generated prompt.
|
||||||
|
|
||||||
|
```markdown, implement-fabric-rti-changes.prompt.md
|
||||||
|
---
|
||||||
|
mode: agent
|
||||||
|
title: Implement microsoft fabric realtime intelligence terraform support
|
||||||
|
---
|
||||||
|
/implement-fabric-rti-blueprint-modification phaseStop=true
|
||||||
|
```
|
||||||
|
|
||||||
|
This prompt has the added benefit of attaching the plan as instructions, which helps with keeping the plan in context throughout the whole conversation.
|
||||||
|
|
||||||
|
**Expert Warning** ->>Use `phaseStop=false` to have Copilot implement the whole plan without stopping. Additionally, you can use `taskStop=true` to have Copilot stop after every Task implementation for finer detail control.
|
||||||
|
|
||||||
|
To use these generated instructions and prompts, you'll need to update your `settings.json` accordingly:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"chat.instructionsFilesLocations": {
|
||||||
|
// Existing instructions folders...
|
||||||
|
".copilot-tracking/plans": true
|
||||||
|
},
|
||||||
|
"chat.promptFilesLocations": {
|
||||||
|
// Existing prompts folders...
|
||||||
|
".copilot-tracking/prompts": true
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*This collection includes 3 curated items for tasks by microsoft/edge-ai.*
|
||||||
142
update-readme.js
142
update-readme.js
@ -142,7 +142,10 @@ function extractTitle(filePath) {
|
|||||||
|
|
||||||
// Track code blocks to ignore headings inside them
|
// Track code blocks to ignore headings inside them
|
||||||
if (frontmatterEnded2) {
|
if (frontmatterEnded2) {
|
||||||
if (line.trim().startsWith("```") || line.trim().startsWith("````")) {
|
if (
|
||||||
|
line.trim().startsWith("```") ||
|
||||||
|
line.trim().startsWith("````")
|
||||||
|
) {
|
||||||
inCodeBlock = !inCodeBlock;
|
inCodeBlock = !inCodeBlock;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -156,7 +159,10 @@ function extractTitle(filePath) {
|
|||||||
// No frontmatter, look for first heading (but not in code blocks)
|
// No frontmatter, look for first heading (but not in code blocks)
|
||||||
let inCodeBlock = false;
|
let inCodeBlock = false;
|
||||||
for (const line of lines) {
|
for (const line of lines) {
|
||||||
if (line.trim().startsWith("```") || line.trim().startsWith("````")) {
|
if (
|
||||||
|
line.trim().startsWith("```") ||
|
||||||
|
line.trim().startsWith("````")
|
||||||
|
) {
|
||||||
inCodeBlock = !inCodeBlock;
|
inCodeBlock = !inCodeBlock;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -260,7 +266,9 @@ function extractDescription(filePath) {
|
|||||||
let description = descriptionMatch[1];
|
let description = descriptionMatch[1];
|
||||||
|
|
||||||
// Check if the description is wrapped in single quotes and handle escaped quotes
|
// Check if the description is wrapped in single quotes and handle escaped quotes
|
||||||
const singleQuoteMatch = line.match(/^description:\s*'(.+?)'\s*$/);
|
const singleQuoteMatch = line.match(
|
||||||
|
/^description:\s*'(.+?)'\s*$/
|
||||||
|
);
|
||||||
if (singleQuoteMatch) {
|
if (singleQuoteMatch) {
|
||||||
// Replace escaped single quotes ('') with single quotes (')
|
// Replace escaped single quotes ('') with single quotes (')
|
||||||
description = singleQuoteMatch[1].replace(/''/g, "'");
|
description = singleQuoteMatch[1].replace(/''/g, "'");
|
||||||
@ -308,8 +316,12 @@ const AKA_INSTALL_URLS = {
|
|||||||
function makeBadges(link, type) {
|
function makeBadges(link, type) {
|
||||||
const aka = AKA_INSTALL_URLS[type] || AKA_INSTALL_URLS.instructions;
|
const aka = AKA_INSTALL_URLS[type] || AKA_INSTALL_URLS.instructions;
|
||||||
|
|
||||||
const vscodeUrl = `${aka}?url=${encodeURIComponent(`vscode:chat-${type}/install?url=${repoBaseUrl}/${link}`)}`;
|
const vscodeUrl = `${aka}?url=${encodeURIComponent(
|
||||||
const insidersUrl = `${aka}?url=${encodeURIComponent(`vscode-insiders:chat-${type}/install?url=${repoBaseUrl}/${link}`)}`;
|
`vscode:chat-${type}/install?url=${repoBaseUrl}/${link}`
|
||||||
|
)}`;
|
||||||
|
const insidersUrl = `${aka}?url=${encodeURIComponent(
|
||||||
|
`vscode-insiders:chat-${type}/install?url=${repoBaseUrl}/${link}`
|
||||||
|
)}`;
|
||||||
|
|
||||||
return `[](${vscodeUrl})<br />[](${insidersUrl})`;
|
return `[](${vscodeUrl})<br />[](${insidersUrl})`;
|
||||||
}
|
}
|
||||||
@ -405,8 +417,7 @@ function generatePromptsSection(promptsDir) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create table header
|
// Create table header
|
||||||
let promptsContent =
|
let promptsContent = "| Title | Description |\n| ----- | ----------- |\n";
|
||||||
"| Title | Description |\n| ----- | ----------- |\n";
|
|
||||||
|
|
||||||
// Generate table rows for each prompt file
|
// Generate table rows for each prompt file
|
||||||
for (const entry of promptEntries) {
|
for (const entry of promptEntries) {
|
||||||
@ -462,8 +473,7 @@ function generateChatModesSection(chatmodesDir) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create table header
|
// Create table header
|
||||||
let chatmodesContent =
|
let chatmodesContent = "| Title | Description |\n| ----- | ----------- |\n";
|
||||||
"| Title | Description |\n| ----- | ----------- |\n";
|
|
||||||
|
|
||||||
// Generate table rows for each chat mode file
|
// Generate table rows for each chat mode file
|
||||||
for (const entry of chatmodeEntries) {
|
for (const entry of chatmodeEntries) {
|
||||||
@ -502,19 +512,22 @@ function generateCollectionsSection(collectionsDir) {
|
|||||||
.filter((file) => file.endsWith(".collection.yml"));
|
.filter((file) => file.endsWith(".collection.yml"));
|
||||||
|
|
||||||
// Map collection files to objects with name for sorting
|
// Map collection files to objects with name for sorting
|
||||||
const collectionEntries = collectionFiles.map((file) => {
|
const collectionEntries = collectionFiles
|
||||||
const filePath = path.join(collectionsDir, file);
|
.map((file) => {
|
||||||
const collection = parseCollectionYaml(filePath);
|
const filePath = path.join(collectionsDir, file);
|
||||||
|
const collection = parseCollectionYaml(filePath);
|
||||||
|
|
||||||
if (!collection) {
|
if (!collection) {
|
||||||
console.warn(`Failed to parse collection: ${file}`);
|
console.warn(`Failed to parse collection: ${file}`);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const collectionId = collection.id || path.basename(file, ".collection.yml");
|
const collectionId =
|
||||||
const name = collection.name || collectionId;
|
collection.id || path.basename(file, ".collection.yml");
|
||||||
return { file, filePath, collection, collectionId, name };
|
const name = collection.name || collectionId;
|
||||||
}).filter(entry => entry !== null); // Remove failed parses
|
return { file, filePath, collection, collectionId, name };
|
||||||
|
})
|
||||||
|
.filter((entry) => entry !== null); // Remove failed parses
|
||||||
|
|
||||||
// Sort by name alphabetically
|
// Sort by name alphabetically
|
||||||
collectionEntries.sort((a, b) => a.name.localeCompare(b.name));
|
collectionEntries.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
@ -566,6 +579,9 @@ function generateCollectionReadme(collection, collectionId) {
|
|||||||
content += `## Items in this Collection\n\n`;
|
content += `## Items in this Collection\n\n`;
|
||||||
content += `| Title | Type | Description |\n| ----- | ---- | ----------- |\n`;
|
content += `| Title | Type | Description |\n| ----- | ---- | ----------- |\n`;
|
||||||
|
|
||||||
|
let collectionUsageHeader = "## Collection Usage\n\n";
|
||||||
|
let collectionUsageContent = [];
|
||||||
|
|
||||||
// Sort items based on display.ordering setting
|
// Sort items based on display.ordering setting
|
||||||
const items = [...collection.items];
|
const items = [...collection.items];
|
||||||
if (collection.display?.ordering === "alpha") {
|
if (collection.display?.ordering === "alpha") {
|
||||||
@ -580,19 +596,52 @@ function generateCollectionReadme(collection, collectionId) {
|
|||||||
const filePath = path.join(__dirname, item.path);
|
const filePath = path.join(__dirname, item.path);
|
||||||
const title = extractTitle(filePath);
|
const title = extractTitle(filePath);
|
||||||
const description = extractDescription(filePath) || "No description";
|
const description = extractDescription(filePath) || "No description";
|
||||||
const typeDisplay = item.kind === "chat-mode" ? "Chat Mode" :
|
|
||||||
item.kind === "instruction" ? "Instruction" : "Prompt";
|
const typeDisplay =
|
||||||
|
item.kind === "chat-mode"
|
||||||
|
? "Chat Mode"
|
||||||
|
: item.kind === "instruction"
|
||||||
|
? "Instruction"
|
||||||
|
: "Prompt";
|
||||||
const link = `../${item.path}`;
|
const link = `../${item.path}`;
|
||||||
|
|
||||||
// Create install badges for each item
|
// Create install badges for each item
|
||||||
const badges = makeBadges(item.path, item.kind === "instruction" ? "instructions" :
|
const badges = makeBadges(
|
||||||
item.kind === "chat-mode" ? "mode" : "prompt");
|
item.path,
|
||||||
|
item.kind === "instruction"
|
||||||
|
? "instructions"
|
||||||
|
: item.kind === "chat-mode"
|
||||||
|
? "mode"
|
||||||
|
: "prompt"
|
||||||
|
);
|
||||||
|
|
||||||
content += `| [${title}](${link})<br />${badges} | ${typeDisplay} | ${description} |\n`;
|
const usageDescription = item.usage
|
||||||
|
? `${description} [see usage](#${title
|
||||||
|
.replace(/\s+/g, "-")
|
||||||
|
.toLowerCase()})`
|
||||||
|
: description;
|
||||||
|
|
||||||
|
content += `| [${title}](${link})<br />${badges} | ${typeDisplay} | ${usageDescription} |\n`;
|
||||||
|
// Generate Usage section for each collection
|
||||||
|
if (item.usage && item.usage.trim()) {
|
||||||
|
collectionUsageContent.push(
|
||||||
|
`### ${title}\n\n${item.usage.trim()}\n\n---\n\n`
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Append the usage section if any items had usage defined
|
||||||
|
if (collectionUsageContent.length > 0) {
|
||||||
|
content += `\n${collectionUsageHeader}${collectionUsageContent.join("")}`;
|
||||||
|
} else if (collection.display?.show_badge) {
|
||||||
|
content += "\n---\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional badge note at the end if show_badge is true
|
||||||
if (collection.display?.show_badge) {
|
if (collection.display?.show_badge) {
|
||||||
content += `\n---\n*This collection includes ${items.length} curated items for ${name.toLowerCase()}.*`;
|
content += `*This collection includes ${
|
||||||
|
items.length
|
||||||
|
} curated items for ${name.toLowerCase()}.*`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
@ -604,12 +653,16 @@ function writeFileIfChanged(filePath, content) {
|
|||||||
if (exists) {
|
if (exists) {
|
||||||
const original = fs.readFileSync(filePath, "utf8");
|
const original = fs.readFileSync(filePath, "utf8");
|
||||||
if (original === content) {
|
if (original === content) {
|
||||||
console.log(`${path.basename(filePath)} is already up to date. No changes needed.`);
|
console.log(
|
||||||
|
`${path.basename(filePath)} is already up to date. No changes needed.`
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fs.writeFileSync(filePath, content);
|
fs.writeFileSync(filePath, content);
|
||||||
console.log(`${path.basename(filePath)} ${exists ? "updated" : "created"} successfully!`);
|
console.log(
|
||||||
|
`${path.basename(filePath)} ${exists ? "updated" : "created"} successfully!`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build per-category README content using existing generators, upgrading headings to H1
|
// Build per-category README content using existing generators, upgrading headings to H1
|
||||||
@ -633,10 +686,16 @@ try {
|
|||||||
const collectionsDir = path.join(__dirname, "collections");
|
const collectionsDir = path.join(__dirname, "collections");
|
||||||
|
|
||||||
// Compose headers for standalone files by converting section headers to H1
|
// Compose headers for standalone files by converting section headers to H1
|
||||||
const instructionsHeader = TEMPLATES.instructionsSection.replace(/^##\s/m, "# ");
|
const instructionsHeader = TEMPLATES.instructionsSection.replace(
|
||||||
|
/^##\s/m,
|
||||||
|
"# "
|
||||||
|
);
|
||||||
const promptsHeader = TEMPLATES.promptsSection.replace(/^##\s/m, "# ");
|
const promptsHeader = TEMPLATES.promptsSection.replace(/^##\s/m, "# ");
|
||||||
const chatmodesHeader = TEMPLATES.chatmodesSection.replace(/^##\s/m, "# ");
|
const chatmodesHeader = TEMPLATES.chatmodesSection.replace(/^##\s/m, "# ");
|
||||||
const collectionsHeader = TEMPLATES.collectionsSection.replace(/^##\s/m, "# ");
|
const collectionsHeader = TEMPLATES.collectionsSection.replace(
|
||||||
|
/^##\s/m,
|
||||||
|
"# "
|
||||||
|
);
|
||||||
|
|
||||||
const instructionsReadme = buildCategoryReadme(
|
const instructionsReadme = buildCategoryReadme(
|
||||||
generateInstructionsSection,
|
generateInstructionsSection,
|
||||||
@ -666,10 +725,19 @@ try {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Write category outputs
|
// Write category outputs
|
||||||
writeFileIfChanged(path.join(__dirname, "README.instructions.md"), instructionsReadme);
|
writeFileIfChanged(
|
||||||
|
path.join(__dirname, "README.instructions.md"),
|
||||||
|
instructionsReadme
|
||||||
|
);
|
||||||
writeFileIfChanged(path.join(__dirname, "README.prompts.md"), promptsReadme);
|
writeFileIfChanged(path.join(__dirname, "README.prompts.md"), promptsReadme);
|
||||||
writeFileIfChanged(path.join(__dirname, "README.chatmodes.md"), chatmodesReadme);
|
writeFileIfChanged(
|
||||||
writeFileIfChanged(path.join(__dirname, "README.collections.md"), collectionsReadme);
|
path.join(__dirname, "README.chatmodes.md"),
|
||||||
|
chatmodesReadme
|
||||||
|
);
|
||||||
|
writeFileIfChanged(
|
||||||
|
path.join(__dirname, "README.collections.md"),
|
||||||
|
collectionsReadme
|
||||||
|
);
|
||||||
|
|
||||||
// Generate individual collection README files
|
// Generate individual collection README files
|
||||||
if (fs.existsSync(collectionsDir)) {
|
if (fs.existsSync(collectionsDir)) {
|
||||||
@ -684,8 +752,12 @@ try {
|
|||||||
const collection = parseCollectionYaml(filePath);
|
const collection = parseCollectionYaml(filePath);
|
||||||
|
|
||||||
if (collection) {
|
if (collection) {
|
||||||
const collectionId = collection.id || path.basename(file, ".collection.yml");
|
const collectionId =
|
||||||
const readmeContent = generateCollectionReadme(collection, collectionId);
|
collection.id || path.basename(file, ".collection.yml");
|
||||||
|
const readmeContent = generateCollectionReadme(
|
||||||
|
collection,
|
||||||
|
collectionId
|
||||||
|
);
|
||||||
const readmeFile = path.join(collectionsDir, `${collectionId}.md`);
|
const readmeFile = path.join(collectionsDir, `${collectionId}.md`);
|
||||||
writeFileIfChanged(readmeFile, readmeContent);
|
writeFileIfChanged(readmeFile, readmeContent);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,45 @@ function parseCollectionYaml(filePath) {
|
|||||||
let currentArray = null;
|
let currentArray = null;
|
||||||
let currentObject = null;
|
let currentObject = null;
|
||||||
|
|
||||||
|
const readLiteralBlock = (startIndex, parentIndent) => {
|
||||||
|
const blockLines = [];
|
||||||
|
let blockIndent = null;
|
||||||
|
let index = startIndex;
|
||||||
|
|
||||||
|
for (; index < lines.length; index++) {
|
||||||
|
const rawLine = lines[index];
|
||||||
|
const trimmedLine = rawLine.trimEnd();
|
||||||
|
const contentOnly = trimmedLine.trim();
|
||||||
|
const lineIndent = rawLine.length - rawLine.trimLeft().length;
|
||||||
|
|
||||||
|
if (contentOnly === "" && blockIndent === null) {
|
||||||
|
// Preserve leading blank lines inside the literal block
|
||||||
|
blockLines.push("");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contentOnly !== "" && lineIndent <= parentIndent) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contentOnly === "") {
|
||||||
|
blockLines.push("");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blockIndent === null) {
|
||||||
|
blockIndent = lineIndent;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockLines.push(rawLine.slice(blockIndent));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: blockLines.join("\n").replace(/\r/g, "").trimEnd(),
|
||||||
|
nextIndex: index - 1,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
for (let i = 0; i < lines.length; i++) {
|
for (let i = 0; i < lines.length; i++) {
|
||||||
const line = lines[i];
|
const line = lines[i];
|
||||||
const trimmed = line.trim();
|
const trimmed = line.trim();
|
||||||
@ -82,6 +121,10 @@ function parseCollectionYaml(filePath) {
|
|||||||
result[key] = [];
|
result[key] = [];
|
||||||
}
|
}
|
||||||
currentKey = null; // Reset since we handled the array
|
currentKey = null; // Reset since we handled the array
|
||||||
|
} else if (value === "|" || value === ">") {
|
||||||
|
const { content: blockContent, nextIndex } = readLiteralBlock(i + 1, leadingSpaces);
|
||||||
|
result[key] = blockContent;
|
||||||
|
i = nextIndex;
|
||||||
} else {
|
} else {
|
||||||
result[key] = value;
|
result[key] = value;
|
||||||
}
|
}
|
||||||
@ -95,10 +138,22 @@ function parseCollectionYaml(filePath) {
|
|||||||
}
|
}
|
||||||
} else if (currentObject && leadingSpaces > 0) {
|
} else if (currentObject && leadingSpaces > 0) {
|
||||||
// Property of current object (e.g., display properties)
|
// Property of current object (e.g., display properties)
|
||||||
currentObject[key] = value === "true" ? true : value === "false" ? false : value;
|
if (value === "|" || value === ">") {
|
||||||
|
const { content: blockContent, nextIndex } = readLiteralBlock(i + 1, leadingSpaces);
|
||||||
|
currentObject[key] = blockContent;
|
||||||
|
i = nextIndex;
|
||||||
|
} else {
|
||||||
|
currentObject[key] = value === "true" ? true : value === "false" ? false : value;
|
||||||
|
}
|
||||||
} else if (currentArray && currentObject && leadingSpaces > 2) {
|
} else if (currentArray && currentObject && leadingSpaces > 2) {
|
||||||
// Property of array item object
|
// Property of array item object
|
||||||
currentObject[key] = value;
|
if (value === "|" || value === ">") {
|
||||||
|
const { content: blockContent, nextIndex } = readLiteralBlock(i + 1, leadingSpaces);
|
||||||
|
currentObject[key] = blockContent;
|
||||||
|
i = nextIndex;
|
||||||
|
} else {
|
||||||
|
currentObject[key] = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user