Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
83 changes: 83 additions & 0 deletions packages/content-ops/src/markdown/link-processor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,89 @@ it('should preserve encoded query and anchor characters when normalizing', async
expect(replacements[0].kind).toBe('normalizedRel')
})

describe('generateNormalizationReplacements - no full normalization', () => {
it('should NOT convert cross-folder relative paths to docsFolders-based paths', async function () {
// Scenario: a skill file in .skills/ references a file in .pair/ using a correct relative path.
// The normalizer should NOT rewrite it to a .pair/-prefix path because that breaks
// navigability in IDEs, GitHub, and the link rewriter during distribution.
const fs = new InMemoryFileSystemService(
{
'/dataset/.pair/adoption/tech/way-of-working.md': '# Way of Working',
'/dataset/.skills/capability/verify-quality/SKILL.md':
'See [wow](../../../.pair/adoption/tech/way-of-working.md).',
},
'/',
'/',
)

const links: ParsedLink[] = [
{
href: '../../../.pair/adoption/tech/way-of-working.md',
text: 'wow',
line: 1,
start: 4,
end: 60,
},
]

const config: LinkProcessingConfig = {
docsFolders: ['.pair', '.skills', '.github'],
datasetRoot: '/dataset',
exclusionList: [],
}

const replacements = await LinkProcessor.generateNormalizationReplacements(
links,
'/dataset/.skills/capability/verify-quality/SKILL.md',
config,
fs,
)

// The relative path is already correct and navigable — no replacement should be generated
expect(replacements).toHaveLength(0)
})

it('should still normalize redundant relative paths within the same folder', async function () {
// Scenario: a file references a sibling with ../same-dir/ prefix — can be simplified
const fs = new InMemoryFileSystemService(
{
'/dataset/.pair/knowledge/how-to/guide.md': '# Guide',
'/dataset/.pair/knowledge/how-to/other.md': 'See [guide](../how-to/guide.md).',
},
'/',
'/',
)

const links: ParsedLink[] = [
{
href: '../how-to/guide.md',
text: 'guide',
line: 1,
start: 4,
end: 30,
},
]

const config: LinkProcessingConfig = {
docsFolders: ['.pair', '.skills'],
datasetRoot: '/dataset',
exclusionList: [],
}

const replacements = await LinkProcessor.generateNormalizationReplacements(
links,
'/dataset/.pair/knowledge/how-to/other.md',
config,
fs,
)

// ../how-to/guide.md → guide.md (same directory, simpler relative path)
expect(replacements).toHaveLength(1)
expect(replacements[0].newHref).toBe('guide.md')
expect(replacements[0].kind).toBe('normalizedRel')
})
})

describe('LinkProcessor - detectLinkStyle', () => {
const cwd = '/test'

Expand Down
52 changes: 4 additions & 48 deletions packages/content-ops/src/markdown/link-processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,19 +235,6 @@ export class LinkProcessor {
fileService: FileSystemService
query: string
anchor: string
}) {
return this.handleFullNormalization(params)
}

private static async handleFullNormalization(params: {
replacements: Replacement[]
lnk: ParsedLink
linkPath: string
absTarget: string
config: LinkProcessingConfig
fileService: FileSystemService
query: string
anchor: string
}) {
const { replacements, lnk, linkPath, absTarget, config, fileService, anchor } = params
const { query } = params
Expand All @@ -269,19 +256,12 @@ export class LinkProcessor {
normalized,
relToDocs,
})
return
}

// handle multi-file path normalization
await this.tryPushMultiFileNormalization({
replacements,
lnk,
linkPath,
absTarget,
config,
fileService,
normalized,
})
// Multi-file path normalization (converting relative paths to docsFolders-based
// paths like .pair/adoption/tech/...) is intentionally disabled. These non-standard
// paths are not navigable in IDEs/GitHub and break the link rewriter during skill
// distribution. Relative paths (e.g., ../../../.pair/...) are correct and work everywhere.
}

private static async tryPushSingleFileNormalization(params: {
Expand All @@ -308,30 +288,6 @@ export class LinkProcessor {
}
}

private static async tryPushMultiFileNormalization(params: {
replacements: Replacement[]
lnk: ParsedLink
linkPath: string
absTarget: string
config: LinkProcessingConfig
fileService: FileSystemService
normalized: string
}) {
const { replacements, lnk, linkPath, absTarget, config, fileService, normalized } = params
const topFolder = normalized.split('/')[0] ?? ''
if (!config.docsFolders.includes(topFolder)) return
if (!(await fileService.exists(absTarget))) return
if (linkPath !== normalized) {
this.pushNormalizedReplacement({
replacements,
lnk,
oldHref: linkPath,
newHref: normalized,
kind: 'normalizedFull',
})
}
}

private static isSkippableLink(url: string, config: LinkProcessingConfig) {
return (
!url ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,10 @@ describe('generateNormalizationReplacements - basics', () => {
fs,
)

expect(replacements).toHaveLength(2)
expect(replacements[0].newHref).toBe('api/ref.md')
expect(replacements[1].newHref).toBe('other.md')
// Only normalizedRel (./other.md → other.md) should be generated.
// ../api/ref.md is already a correct relative path — no full normalization.
expect(replacements).toHaveLength(1)
expect(replacements[0].newHref).toBe('other.md')
})
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ You are a Product Engineer working in an AI-assisted development process followi
Based on the how-to guides, you handle these development and implementation activities:

### ⚙️ **Task & Implementation Management (Your Primary Domain)**
- **Create Tasks** → [09-how-to-create-tasks.md](.pair/knowledge/how-to/09-how-to-create-tasks.md)
- **Create Tasks** → [09-how-to-create-tasks.md](../../.pair/knowledge/how-to/09-how-to-create-tasks.md)
- *Role: Product Engineer (Story Implementation Planning)*
- **Implement Tasks** → [10-how-to-implement-a-task.md](.pair/knowledge/how-to/10-how-to-implement-a-task.md)
- **Implement Tasks** → [10-how-to-implement-a-task.md](../../.pair/knowledge/how-to/10-how-to-implement-a-task.md)
- *Role: Product Software Engineer (Implementation)*

### 📝 **Story Collaboration**
- **Refine User Stories** → [08-how-to-refine-a-user-story.md](.pair/knowledge/how-to/08-how-to-refine-a-user-story.md)
- **Refine User Stories** → [08-how-to-refine-a-user-story.md](../../.pair/knowledge/how-to/08-how-to-refine-a-user-story.md)
- *Role: Product Engineer (Technical Refinement)*
- *Note: Collaborate with Product Manager on technical aspects*

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@ You are a Product Manager working in an AI-assisted development process followin
Based on the how-to guides, you handle these strategic and planning activities:

### 🎯 **Strategic Planning (Your Primary Domain)**
- **Create PRD** → [01-how-to-create-PRD.md](.pair/knowledge/how-to/01-how-to-create-PRD.md)
- **Create PRD** → [01-how-to-create-PRD.md](../../.pair/knowledge/how-to/01-how-to-create-PRD.md)
- *Role: Product Manager (PRD Creation)*
- **Create and Prioritize Initiatives** → [03-how-to-create-and-prioritize-initiatives.md](.pair/knowledge/how-to/03-how-to-create-and-prioritize-initiatives.md)
- **Create and Prioritize Initiatives** → [03-how-to-create-and-prioritize-initiatives.md](../../.pair/knowledge/how-to/03-how-to-create-and-prioritize-initiatives.md)
- *Role: Product Owner/Manager (Strategic Decomposition)*
- **Define Subdomains** → [04-how-to-define-subdomains.md](.pair/knowledge/how-to/04-how-to-define-subdomains.md)
- **Define Subdomains** → [04-how-to-define-subdomains.md](../../.pair/knowledge/how-to/04-how-to-define-subdomains.md)
- *Role: Product Manager (Domain Modeling)*

### 📋 **Epic & Story Management**
- **Breakdown Epics** → [06-how-to-breakdown-epics.md](.pair/knowledge/how-to/06-how-to-breakdown-epics.md)
- **Breakdown Epics** → [06-how-to-breakdown-epics.md](../../.pair/knowledge/how-to/06-how-to-breakdown-epics.md)
- *Role: Product Owner/Manager (Strategic Decomposition)*
- **Breakdown User Stories** → [07-how-to-breakdown-user-stories.md](.pair/knowledge/how-to/07-how-to-breakdown-user-stories.md)
- **Breakdown User Stories** → [07-how-to-breakdown-user-stories.md](../../.pair/knowledge/how-to/07-how-to-breakdown-user-stories.md)
- *Role: Product Manager (Story Creation)*
- **Refine User Stories** → [08-how-to-refine-a-user-story.md](.pair/knowledge/how-to/08-how-to-refine-a-user-story.md)
- **Refine User Stories** → [08-how-to-refine-a-user-story.md](../../.pair/knowledge/how-to/08-how-to-refine-a-user-story.md)
- *Role: Product Manager (Story Refinement)*

## Process Guidelines
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ You are helping define bounded contexts that translate business subdomains into

## Process

**Read and follow** the complete process from [how-to-define-bounded-contexts.md](.pair/knowledge/how-to/05-how-to-define-bounded-contexts.md).
**Read and follow** the complete process from [how-to-define-bounded-contexts.md](../../.pair/knowledge/how-to/05-how-to-define-bounded-contexts.md).

**Execute the process exactly as documented**, including:
- All phases and checkpoints
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ If an initiative ID is provided (e.g., `/breakdown-epics: initiative_id=INIT-123

## Process

**Read and follow** the complete process from [how-to-breakdown-epics.md](.pair/knowledge/how-to/06-how-to-breakdown-epics.md).
**Read and follow** the complete process from [how-to-breakdown-epics.md](../../.pair/knowledge/how-to/06-how-to-breakdown-epics.md).

**Execute the process exactly as documented**, including:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ If an epic ID is provided (e.g., `/breakdown-stories: epic_id=EPIC-123`), focus

## Process

**Read and follow** the complete process from [how-to-breakdown-user-stories.md](.pair/knowledge/how-to/07-how-to-breakdown-user-stories.md).
**Read and follow** the complete process from [how-to-breakdown-user-stories.md](../../.pair/knowledge/how-to/07-how-to-breakdown-user-stories.md).

**Execute the process exactly as documented**, including:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ If a story ID is provided (e.g., `/code-review: story_id=STORY-456`), search for

## Process

**Read and follow** the complete process from [how-to-code-review.md](.pair/knowledge/how-to/11-how-to-code-review.md).
**Read and follow** the complete process from [how-to-code-review.md](../../.pair/knowledge/how-to/11-how-to-code-review.md).

**Execute the process exactly as documented**, including:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ You are helping complete the bootstrap checklist to establish a solid project fo

## Process

**Read and follow** the complete process from [how-to-complete-bootstrap-checklist.md](.pair/knowledge/how-to/02-how-to-complete-bootstrap-checklist.md).
**Read and follow** the complete process from [how-to-complete-bootstrap-checklist.md](../../.pair/knowledge/how-to/02-how-to-complete-bootstrap-checklist.md).

**Execute the process exactly as documented**, including:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ You are helping create a Product Requirements Document (PRD) for a product or fe

## Process

**Read and follow** the complete process from [how-to-create-PRD.md](.pair/knowledge/how-to/01-how-to-create-PRD.md).
**Read and follow** the complete process from [how-to-create-PRD.md](../../.pair/knowledge/how-to/01-how-to-create-PRD.md).

**Execute the process exactly as documented**, including:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ You are helping create and prioritize strategic initiatives that translate PRD r

## Process

**Read and follow** the complete process from [how-to-create-and-prioritize-initiatives.md](.pair/knowledge/how-to/03-how-to-create-and-prioritize-initiatives.md).
**Read and follow** the complete process from [how-to-create-and-prioritize-initiatives.md](../../.pair/knowledge/how-to/03-how-to-create-and-prioritize-initiatives.md).

**Execute the process exactly as documented**, including:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ If a story ID is provided (e.g., `/create-tasks: story_id=STORY-123`), focus on

## Process

**Read and follow** the complete process from [how-to-create-tasks.md](.pair/knowledge/how-to/09-how-to-create-tasks.md).
**Read and follow** the complete process from [how-to-create-tasks.md](../../.pair/knowledge/how-to/09-how-to-create-tasks.md).

**Execute the process exactly as documented**, including:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ You are helping define bounded contexts that translate business subdomains into

## Process

**Read and follow** the complete process from [how-to-define-bounded-contexts.md](.pair/knowledge/how-to/05-how-to-define-bounded-contexts.md).
**Read and follow** the complete process from [how-to-define-bounded-contexts.md](../../.pair/knowledge/how-to/05-how-to-define-bounded-contexts.md).

**Execute the process exactly as documented**, including:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ You are helping define business subdomains to create a clear domain model for th

## Process

**Read and follow** the complete process from [how-to-define-subdomains.md](.pair/knowledge/how-to/04-how-to-define-subdomains.md).
**Read and follow** the complete process from [how-to-define-subdomains.md](../../.pair/knowledge/how-to/04-how-to-define-subdomains.md).

**Execute the process exactly as documented**, including:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ You are helping create and prioritize strategic initiatives that translate PRD r

## Process

**Read and follow** the complete process from [how-to-create-and-prioritize-initiatives.md](.pair/knowledge/how-to/03-how-to-create-and-prioritize-initiatives.md).
**Read and follow** the complete process from [how-to-create-and-prioritize-initiatives.md](../../.pair/knowledge/how-to/03-how-to-create-and-prioritize-initiatives.md).

**Execute the process exactly as documented**, including:
- All phases and checkpoints
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ If a story ID is provided (e.g., `/refine-story: story_id=STORY-123`), focus on

## Process

**Read and follow** the complete process from [how-to-refine-a-user-story.md](.pair/knowledge/how-to/08-how-to-refine-a-user-story.md).
**Read and follow** the complete process from [how-to-refine-a-user-story.md](../../.pair/knowledge/how-to/08-how-to-refine-a-user-story.md).

**Execute the process exactly as documented**, including:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ You are helping define business subdomains to create a clear domain model for th

## Process

**Read and follow** the complete process from [how-to-define-subdomains.md](.pair/knowledge/how-to/04-how-to-define-subdomains.md).
**Read and follow** the complete process from [how-to-define-subdomains.md](../../.pair/knowledge/how-to/04-how-to-define-subdomains.md).

**Execute the process exactly as documented**, including:
- All phases and checkpoints
Expand Down
34 changes: 17 additions & 17 deletions packages/knowledge-hub/dataset/.pair/adoption/tech/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ All adopted documents must:

- Be written in **English**
- Be **concise**: list only choices and decisions without explanations or rationale
- Reference the [knowledge-base](.pair/knowledge) for details, explanations, and background information
- Reference the [knowledge-base](../../knowledge) for details, explanations, and background information
- Be **self-consistent** with compatible choices across library versions, user device targets, and deployment environments
- Be **strict and prescriptive** with no ambiguity or open interpretation
- Address all relevant points from the [bootstrap-checklist](.pair/knowledge/assets/bootstrap-checklist.md)
- Address all relevant points from the [bootstrap-checklist](../../knowledge/assets/bootstrap-checklist.md)

## 📁 Document Categories

Expand All @@ -35,7 +35,7 @@ These documents are **decision records**, not guidelines:

- Contain only **validated choices** proposed by AI and approved by the team
- Must be **implemented as written** with full compliance required
- Reference the [knowledge-base](.pair/knowledge) for detailed explanations
- Reference the [knowledge-base](../../knowledge) for detailed explanations
- Must reflect the current project state and be kept up to date

## 🔄 Update Process
Expand All @@ -52,21 +52,21 @@ Standards are updated during specific development phases:

Detailed technical guidelines and explanations:

- [architecture/README.md](.pair/knowledge/guidelines/architecture/README.md)
- [02-code-design-guidelines.md](.pair/knowledge/guidelines/code-design/README.md)
- [technical-standards/README.md](.pair/knowledge/guidelines/technical-standards/README.md)
- [infrastructure/README.md](.pair/knowledge/guidelines/infrastructure/README.md)
- [05-ux-guidelines.md](.pair/knowledge/guidelines/user-experience/README.md)
- [06-definition-of-done.md](.pair/knowledge/guidelines/quality-assurance/quality-standards/definition-of-done.md)
- [07-testing-strategy.md](.pair/knowledge/guidelines/testing/test-strategy/README.md)
- [08-accessibility-guidelines.md](.pair/knowledge/guidelines/quality-assurance/accessibility/README.md)
- [09-performance-guidelines.md](.pair/knowledge/guidelines/quality-assurance/performance/README.md)
- [10-security-guidelines.md](.pair/knowledge/guidelines/quality-assurance/security/README.md)
- [11-observability-guidelines.md](.pair/knowledge/guidelines/observability/README.md)
- [README.md](.pair/knowledge/guidelines/README.md) – Knowledge Base Overview
- [architecture/README.md](../../knowledge/guidelines/architecture/README.md)
- [02-code-design-guidelines.md](../../knowledge/guidelines/code-design/README.md)
- [technical-standards/README.md](../../knowledge/guidelines/technical-standards/README.md)
- [infrastructure/README.md](../../knowledge/guidelines/infrastructure/README.md)
- [05-ux-guidelines.md](../../knowledge/guidelines/user-experience/README.md)
- [06-definition-of-done.md](../../knowledge/guidelines/quality-assurance/quality-standards/definition-of-done.md)
- [07-testing-strategy.md](../../knowledge/guidelines/testing/test-strategy/README.md)
- [08-accessibility-guidelines.md](../../knowledge/guidelines/quality-assurance/accessibility/README.md)
- [09-performance-guidelines.md](../../knowledge/guidelines/quality-assurance/performance/README.md)
- [10-security-guidelines.md](../../knowledge/guidelines/quality-assurance/security/README.md)
- [11-observability-guidelines.md](../../knowledge/guidelines/observability/README.md)
- [README.md](../../knowledge/guidelines/README.md) – Knowledge Base Overview

### Additional Resources

- **[Bootstrap Checklist](.pair/knowledge/assets/bootstrap-checklist.md)** – Project Setup & Bootstrap Checklist with all relevant questions the adopted standards must address
- **[Bootstrap Checklist](../../knowledge/assets/bootstrap-checklist.md)** – Project Setup & Bootstrap Checklist with all relevant questions the adopted standards must address
- **[ADR](adr)** – Architecture Decision Records for significant changes
- **[Way of Working](.pair/knowledge/way-of-working.md)** – Development process and collaboration patterns
- **[Way of Working](../../knowledge/way-of-working.md)** – Development process and collaboration patterns
Loading