Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
da1056f
Trim excessive comments in src/article-api lib, middleware, and scrip…
heiskr Sep 15, 2026
140d795
Trim excessive comments in src/content-render/scripts (#63277)
heiskr Sep 15, 2026
3c379b6
Trim excessive comments in src/graphql and src/fixtures (#63275)
heiskr Sep 15, 2026
dd5e7bc
Clean up comments in src/links/scripts (#63272)
heiskr Sep 15, 2026
f1114fe
Trim excessive comments in src/languages (#63268)
heiskr Sep 15, 2026
d6f91cd
Trim excessive comments in src/content-linter scripts and tests (#63267)
heiskr Sep 15, 2026
3342b3d
Trim redundant comments in src/frame/tests and src/data-directory (#6…
heiskr Sep 15, 2026
2701956
Trim redundant comments in src/frame/components (#63262)
heiskr Sep 15, 2026
8757a47
Trim excessive comments in src/frame/lib (#63257)
heiskr Sep 15, 2026
91644b1
Trim redundant comments in tools, archives, versions, tests, and audi…
heiskr Sep 15, 2026
5695f5e
Trim comments in ai-tools, shielding, and automated-pipelines (#63245)
heiskr Sep 15, 2026
54ba6bd
Clean up comments in src/ghes-releases (#63274)
heiskr Sep 15, 2026
f65fee9
Clean up code comments in src/observability source files (#63229)
heiskr Sep 15, 2026
20e9ba9
Trim excessive comments in src/article-api tests (#63280)
heiskr Sep 15, 2026
e3034ac
Trim excessive comments in the rest of src/content-render (#63278)
heiskr Sep 15, 2026
74c7d20
Trim excessive comments in src/frame/middleware (#63259)
heiskr Sep 15, 2026
d79d9d3
Merge pull request #45913 from github/repo-sync
docs-bot Sep 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/ai-tools/lib/auth-utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { execSync } from 'child_process'

/**
* Ensure GitHub token is available, exiting process if not found
* Falls back to the gh CLI token, setting process.env.GITHUB_TOKEN.
* Exits the process if neither is available.
*/
export function ensureGitHubToken(): void {
if (!process.env.GITHUB_TOKEN) {
Expand Down
6 changes: 0 additions & 6 deletions src/ai-tools/lib/call-models-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ export async function callModelsApi(
): Promise<string> {
let aiResponse: ChatCompletionChoice

// Set default model if none specified
if (!promptWithContent.model) {
promptWithContent.model = DEFAULT_MODEL
if (verbose) {
Expand All @@ -51,7 +50,6 @@ export async function callModelsApi(
}

try {
// Create an AbortController for timeout handling
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), API_TIMEOUT_MS)

Expand Down Expand Up @@ -82,7 +80,6 @@ export async function callModelsApi(
if (!response.ok) {
let errorMessage = `HTTP error! status: ${response.status} - ${response.statusText}`

// Try to get more detailed error information
try {
const errorBody = await response.json()
if (errorBody.error && errorBody.error.message) {
Expand All @@ -92,7 +89,6 @@ export async function callModelsApi(
// If we can't parse error body, continue with basic error
}

// Add helpful hints for common errors
if (response.status === 401) {
errorMessage += ' (Check your GITHUB_TOKEN)'
} else if (response.status === 400) {
Expand Down Expand Up @@ -135,9 +131,7 @@ export async function callModelsApi(
return cleanAIResponse(aiResponse.message.content)
}

// Helper function to clean up AI response content
function cleanAIResponse(content: string): string {
// Remove markdown code blocks
return content
.replace(/^```[\w]*\n/gm, '') // Remove opening code blocks
.replace(/\n```$/gm, '') // Remove closing code blocks at end
Expand Down
17 changes: 3 additions & 14 deletions src/ai-tools/lib/file-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ import { schema } from '@/frame/lib/frontmatter'

const MAX_DIRECTORY_DEPTH = 20

/**
* Enhanced recursive markdown file finder with symlink, depth, and root path checks
*/
export function findMarkdownFiles(
dir: string,
rootDir: string,
Expand All @@ -33,7 +30,6 @@ export function findMarkdownFiles(
return []
}
visited.add(realDir)
// Prevent excessive depth
if (depth > maxDepth) {
return []
}
Expand Down Expand Up @@ -71,9 +67,8 @@ interface FrontmatterProperties {
}

/**
* Function to merge new frontmatter properties into existing file while preserving formatting.
* Uses surgical replacement to only modify the specific field(s) being updated,
* preserving all original YAML formatting for unchanged fields.
* Replaces only the fields being updated, so the original YAML formatting
* of every other field survives.
*/
export function mergeFrontmatterProperties(filePath: string, newPropertiesYaml: string): string {
const content = fs.readFileSync(filePath, 'utf8')
Expand All @@ -90,7 +85,7 @@ export function mergeFrontmatterProperties(filePath: string, newPropertiesYaml:
}

try {
// Clean up the AI response - remove markdown code blocks if present
// The model often wraps its output in a code fence.
let cleanedYaml = newPropertiesYaml.trim()
cleanedYaml = cleanedYaml.replace(/^```ya?ml\s*\n/i, '')
cleanedYaml = cleanedYaml.replace(/\n```\s*$/i, '')
Expand All @@ -111,12 +106,10 @@ export function mergeFrontmatterProperties(filePath: string, newPropertiesYaml:
}),
)

// Split content into lines for surgical replacement
const lines = content.split('\n')
let inFrontmatter = false
let frontmatterEndIndex = -1

// Find frontmatter boundaries
for (let i = 0; i < lines.length; i++) {
if (lines[i].trim() === '---') {
if (!inFrontmatter) {
Expand All @@ -128,17 +121,14 @@ export function mergeFrontmatterProperties(filePath: string, newPropertiesYaml:
}
}

// Replace each field value while preserving everything else
for (const [key, value] of Object.entries(sanitizedProperties)) {
const formattedValue = typeof value === 'string' ? `'${value.replace(/'/g, "''")}'` : value

// Find the line with this field
let foundField = false
for (let i = 1; i < frontmatterEndIndex; i++) {
const line = lines[i]
if (line.startsWith(`${key}:`)) {
foundField = true
// Simple replacement: keep the field name and spacing, replace the value
const colonIndex = line.indexOf(':')
const leadingSpace = line.substring(colonIndex + 1, colonIndex + 2) // Usually a space
lines[i] = `${key}:${leadingSpace}${formattedValue}`
Expand All @@ -153,7 +143,6 @@ export function mergeFrontmatterProperties(filePath: string, newPropertiesYaml:
}
}

// If field doesn't exist, add it before the closing ---
if (!foundField && frontmatterEndIndex > 0) {
lines.splice(frontmatterEndIndex, 0, `${key}: ${formattedValue}`)
frontmatterEndIndex++
Expand Down
26 changes: 3 additions & 23 deletions src/ai-tools/lib/prompt-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,11 @@ export interface PromptData {
max_tokens?: number
}

/**
* Get the prompts directory path
*/
export function getPromptsDir(): string {
const __dirname = path.dirname(fileURLToPath(import.meta.url))
return path.join(__dirname, '../prompts')
}

/**
* Dynamically discover available editor types from prompt files
*/
export function getAvailableEditorTypes(promptDir: string): string[] {
const editorTypes: string[] = []

Expand All @@ -46,16 +40,10 @@ export function getAvailableEditorTypes(promptDir: string): string[] {
return editorTypes
}

/**
* Get formatted description of available refinement types
*/
export function getRefinementDescriptions(editorTypes: string[]): string {
return editorTypes.join(', ')
}

/**
* Enrich context for intro prompt on index.md files
*/
export function enrichIndexContext(filePath: string, content: string): string {
if (!filePath.endsWith('index.md')) return content

Expand All @@ -72,7 +60,6 @@ export function enrichIndexContext(filePath: string, content: string): string {
.join(' ')
: ''

// Get child article titles
const titles: string[] = []
if (data.children && Array.isArray(data.children)) {
const dir = path.dirname(filePath)
Expand All @@ -94,7 +81,6 @@ export function enrichIndexContext(filePath: string, content: string): string {
}
}

// Build context note
const parts: string[] = []
if (productName) parts.push(`Product: ${productName}`)
if (titles.length > 0) parts.push(`Child articles: ${titles.join(', ')}`)
Expand All @@ -114,24 +100,19 @@ export function enrichIndexContext(filePath: string, content: string): string {
return content
}

/**
* Call an editor with the given content and options
*/
export async function callEditor(
editorType: string,
content: string,
promptDir: string,
writeMode: boolean,
verbose = false,
promptContent?: string, // Optional: use this instead of reading from file
promptContent?: string, // Use this instead of reading a prompt file
): Promise<string> {
let markdownPrompt: string

if (promptContent) {
// Use provided prompt content (e.g., from Copilot Space)
markdownPrompt = promptContent
} else {
// Read from file
const markdownPromptPath = path.join(promptDir, `${editorType}.md`)

if (!fs.existsSync(markdownPromptPath)) {
Expand All @@ -144,15 +125,15 @@ export async function callEditor(

const prompt = load(fs.readFileSync(promptTemplatePath, 'utf8')) as PromptData

// Validate the prompt template has required properties
if (!prompt.messages || !Array.isArray(prompt.messages)) {
throw new Error('Invalid prompt template: missing or invalid messages array')
}

for (const msg of prompt.messages) {
msg.content = msg.content.replace('{{markdownPrompt}}', markdownPrompt)
msg.content = msg.content.replace('{{input}}', content)
// Replace writeMode template variable with simple string replacement
// Resolve the write-mode markers, then strip whatever they marked
// for removal.
msg.content = msg.content.replace(
/<!-- IF_WRITE_MODE -->/g,
writeMode ? '' : '<!-- REMOVE_START -->',
Expand All @@ -166,7 +147,6 @@ export async function callEditor(
writeMode ? '' : '<!-- REMOVE_END -->',
)

// Remove sections marked for removal
msg.content = msg.content.replace(/<!-- REMOVE_START -->[\s\S]*?<!-- REMOVE_END -->/g, '')
}

Expand Down
15 changes: 0 additions & 15 deletions src/ai-tools/lib/spaces-utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
/**
* Copilot Space API response types
*/
import { fetchWithRetry, readBodyWithTimeout } from '@/frame/lib/fetch-utils'

export interface SpaceResource {
Expand All @@ -25,9 +22,6 @@ export interface SpaceData {
updated_at: string
}

/**
* Parse a Copilot Space URL to extract org and space ID
*/
export function parseSpaceUrl(url: string): { org: string; id: string } {
// Expected format: https://api.github.com/orgs/{org}/copilot-spaces/{id}
const match = url.match(/\/orgs\/([^/]+)\/copilot-spaces\/(\d+)/)
Expand All @@ -44,9 +38,6 @@ export function parseSpaceUrl(url: string): { org: string; id: string } {
}
}

/**
* Fetch a Copilot Space from the GitHub API
*/
export async function fetchCopilotSpace(spaceUrl: string): Promise<SpaceData> {
const { org, id } = parseSpaceUrl(spaceUrl)
const apiUrl = `https://api.github.com/orgs/${org}/copilot-spaces/${id}`
Expand Down Expand Up @@ -88,26 +79,20 @@ export async function fetchCopilotSpace(spaceUrl: string): Promise<SpaceData> {
return (await readBodyWithTimeout(response, () => response.json(), 30_000)) as SpaceData
}

/**
* Convert a Copilot Space to a markdown prompt file
*/
export function convertSpaceToPrompt(space: SpaceData): string {
const timestamp = new Date().toISOString()
const lines: string[] = []

// Header with metadata
lines.push(`<!-- Generated from Copilot Space: ${space.name} -->`)
lines.push(`<!-- Space ID: ${space.number} | Generated: ${timestamp} -->`)
lines.push(`<!-- Space URL: ${space.html_url} -->`)
lines.push('')

// General instructions
if (space.general_instructions) {
lines.push(space.general_instructions.trim())
lines.push('')
}

// Add each resource as a context section
if (space.resources_attributes && space.resources_attributes.length > 0) {
for (const resource of space.resources_attributes) {
if (resource.resource_type === 'free_text' && resource.metadata) {
Expand Down
Loading