Skip to content

feat(riviere-cli): add extract command for component extraction - #88

Merged
NTCoding merged 7 commits into
mainfrom
issue-44-m4-d4-1-add-riviere-extract-co
Jan 9, 2026
Merged

NTCoding merged 7 commits into
mainfrom
issue-44-m4-d4-1-add-riviere-extract-co

Conversation

@NTCoding

@NTCoding NTCoding commented Jan 9, 2026 •

Copy link
Copy Markdown
Owner

User description

Closes #44

Summary

Implements riviere extract --config <path> CLI command that runs component extraction and outputs draft components JSON to stdout.

Changes

  • Added riviere extract command with --config option
  • Handles missing config file with clear ConfigNotFound error
  • Handles invalid YAML with validation error messages
  • Handles invalid schema with detailed validation errors
  • Outputs valid JSON on successful extraction
  • Added comprehensive integration tests

Test Plan

  • ✅ Verify gate passed (lint, typecheck, test)
  • ✅ 100% test coverage
  • ✅ Code review: PASS
  • ✅ Bug scanner: PASS
  • ✅ All acceptance criteria met

Related

Closes #44


PR Type

Enhancement


Description

  • Add riviere extract CLI command for component extraction

  • Implement config validation with YAML parsing and schema checking

  • Output extracted components as JSON to stdout

  • Add comprehensive integration tests with 100% coverage

  • Add new dependencies: glob, ts-morph, yaml for extraction


Diagram Walkthrough

flowchart LR
  CLI["CLI extract command"]
  CONFIG["Load & validate config"]
  EXTRACT["Extract components"]
  OUTPUT["Output JSON"]
  CLI --> CONFIG
  CONFIG --> EXTRACT
  EXTRACT --> OUTPUT
Loading

File Walkthrough

Relevant files
Enhancement
cli.ts
Register extract command in CLI                                                   

packages/riviere-cli/src/cli.ts

  • Import new createExtractCommand from extract module
  • Register extract command at top level of program
  • Extract command added alongside existing query commands
+3/-0     
extract.ts
Implement extract command with config validation                 

packages/riviere-cli/src/commands/extract/extract.ts

  • Implement createExtractCommand() function with --config option
  • Parse and validate YAML config files with error handling
  • Validate extraction config schema using riviere-extract-config
  • Resolve file paths using glob patterns relative to config directory
  • Extract components using ts-morph and riviere-extract-ts
  • Output results as JSON to stdout
+105/-0 
error-codes.ts
Add ConfigNotFound error code                                                       

packages/riviere-cli/src/error-codes.ts

  • Add new ConfigNotFound error code to CliErrorCode enum
  • Used for missing extraction config file errors
+1/-0     
Tests
extract.spec.ts
Add comprehensive extract command tests                                   

packages/riviere-cli/src/commands/extract/extract.spec.ts

  • Add 152 lines of comprehensive integration tests
  • Test command registration at top level
  • Test missing config file error handling
  • Test invalid YAML parsing error handling
  • Test invalid schema validation error handling
  • Test successful component extraction with real source files
  • Verify JSON output format and component data structure
+152/-0 
Dependencies
package.json
Add extract command dependencies                                                 

packages/riviere-cli/package.json

  • Add @living-architecture/riviere-extract-config workspace dependency
  • Add @living-architecture/riviere-extract-ts workspace dependency
  • Add glob ^11.0.2 for file pattern matching
  • Add ts-morph ^24.0.0 for TypeScript AST manipulation
  • Add yaml ^2.7.0 for YAML parsing
+6/-1     
pnpm-lock.yaml
Update lock file with new dependencies                                     

pnpm-lock.yaml

+104/-0 
Configuration changes
tsconfig.lib.json
Add TypeScript references for extract packages                     

packages/riviere-cli/tsconfig.lib.json

  • Add TypeScript project reference to riviere-extract-ts
  • Add TypeScript project reference to riviere-extract-config
  • Reorder references for consistency
+7/-1     
settings.json
Remove bash script permission                                                       

.claude/settings.json

  • Remove Bash permission for submit-pr.sh script
  • Simplify permissions configuration
+0/-3     

Summary by CodeRabbit

  • New Features
    • Added a new CLI command to extract architectural components from TypeScript sources via YAML configs; outputs JSON results/errors.
  • Tests
    • Added comprehensive tests covering config validation, error scenarios, and successful extraction flows.
  • Documentation
    • CLI reference generation updated to include the new extraction commands and usage snippet.
  • Chores
    • Added runtime/workspace dependencies, updated project references, and narrowed automation permissions by removing a permitted script execution.

✏️ Tip: You can customize this high-level summary in your review settings.

NTCoding and others added 2 commits January 9, 2026 19:44
Implements `riviere extract --config <path>` command that:
- Loads and validates extraction config from YAML
- Runs component extraction using riviere-extract-ts
- Outputs draft components as JSON to stdout
- Provides clear error messages for missing or invalid configs

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@coderabbitai

coderabbitai Bot commented Jan 9, 2026 •

Copy link
Copy Markdown

Warning

Rate limit exceeded

@NTCoding has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 0 minutes and 38 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 0003875 and 2c9255f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (134)
  • apps/eclair/src/App.spec.tsx
  • apps/eclair/src/components/AppShell/AppShell.spec.tsx
  • apps/eclair/src/components/FileUpload/FileUpload.spec.tsx
  • apps/eclair/src/components/Header/Header.spec.tsx
  • apps/eclair/src/components/Logo/Logo.spec.tsx
  • apps/eclair/src/components/OrphanWarning/OrphanWarning.spec.tsx
  • apps/eclair/src/components/SchemaModal/SchemaModal.spec.tsx
  • apps/eclair/src/components/Sidebar/Sidebar.spec.tsx
  • apps/eclair/src/components/ThemeSwitcher/ThemeSwitcher.spec.tsx
  • apps/eclair/src/contexts/ExportContext.spec.tsx
  • apps/eclair/src/contexts/GraphContext.spec.tsx
  • apps/eclair/src/contexts/ThemeContext.spec.tsx
  • apps/eclair/src/features/comparison/ChangeFilters.spec.tsx
  • apps/eclair/src/features/comparison/ComparisonPage.detailedChanges.spec.tsx
  • apps/eclair/src/features/comparison/ComparisonPage.spec.tsx
  • apps/eclair/src/features/comparison/DomainConnectionDiff.spec.tsx
  • apps/eclair/src/features/comparison/StatsBar.spec.tsx
  • apps/eclair/src/features/comparison/compareGraphs.spec.ts
  • apps/eclair/src/features/comparison/computeDomainConnectionDiff.edgeDetails.spec.ts
  • apps/eclair/src/features/comparison/computeDomainConnectionDiff.spec.ts
  • apps/eclair/src/features/domain-map/DomainMapPage.spec.tsx
  • apps/eclair/src/features/domain-map/calculateTooltipPosition.spec.ts
  • apps/eclair/src/features/domain-map/components/DomainEdge/DomainEdge.spec.tsx
  • apps/eclair/src/features/domain-map/components/DomainNode/DomainNode.spec.tsx
  • apps/eclair/src/features/domain-map/extractDomainMap.external.spec.ts
  • apps/eclair/src/features/domain-map/extractDomainMap.reactflow.spec.ts
  • apps/eclair/src/features/domain-map/extractDomainMap.spec.ts
  • apps/eclair/src/features/domain-map/hooks/useDomainMapInteractions.spec.ts
  • apps/eclair/src/features/domain-map/pluralize.spec.ts
  • apps/eclair/src/features/domains/DomainDetailPage.spec.tsx
  • apps/eclair/src/features/domains/DomainDetailView.spec.tsx
  • apps/eclair/src/features/domains/components/DomainContextGraph/ConnectionItem.spec.tsx
  • apps/eclair/src/features/domains/components/DomainContextGraph/DomainContextGraph.spec.tsx
  • apps/eclair/src/features/domains/components/DomainContextGraph/DomainInfoModal.spec.tsx
  • apps/eclair/src/features/domains/components/DomainContextGraph/DomainNode.spec.tsx
  • apps/eclair/src/features/domains/components/DomainContextGraph/EdgeLine.spec.tsx
  • apps/eclair/src/features/domains/components/DomainDetailModal/DomainDetailModal.spec.tsx
  • apps/eclair/src/features/domains/components/EntityAccordion/EntityAccordion.spec.tsx
  • apps/eclair/src/features/domains/components/EventAccordion/EventAccordion.spec.tsx
  • apps/eclair/src/features/domains/domainNodeBreakdown.spec.ts
  • apps/eclair/src/features/domains/extractDomainDetails.advanced.spec.ts
  • apps/eclair/src/features/domains/extractDomainDetails.entities.spec.ts
  • apps/eclair/src/features/domains/extractDomainDetails.spec.ts
  • apps/eclair/src/features/domains/extractDomainDetails.stateMachine.spec.ts
  • apps/eclair/src/features/empty-state/EmptyState.spec.tsx
  • apps/eclair/src/features/entities/EntitiesPage.spec.tsx
  • apps/eclair/src/features/events/EventsPage.spec.tsx
  • apps/eclair/src/features/flows/FlowsPage.spec.tsx
  • apps/eclair/src/features/flows/components/CodeLinkMenu/CodeLinkMenu.spec.tsx
  • apps/eclair/src/features/flows/components/CodeLinkMenu/ConfigurePathModal.spec.tsx
  • apps/eclair/src/features/flows/components/CodeLinkMenu/useCodeLinkSettings.spec.ts
  • apps/eclair/src/features/flows/components/DomainBadge/DomainBadge.spec.tsx
  • apps/eclair/src/features/flows/components/FlowCard/FlowCard.spec.tsx
  • apps/eclair/src/features/flows/components/FlowTrace/FlowGraphView.spec.tsx
  • apps/eclair/src/features/flows/components/FlowTrace/FlowTrace.spec.tsx
  • apps/eclair/src/features/flows/components/NodeTypeBadge/NodeTypeBadge.spec.tsx
  • apps/eclair/src/features/flows/extractFlows.spec.ts
  • apps/eclair/src/features/flows/hooks/useFlowsState.spec.ts
  • apps/eclair/src/features/full-graph/FullGraphPage.spec.tsx
  • apps/eclair/src/features/full-graph/components/DomainFilters/DomainFilters.spec.tsx
  • apps/eclair/src/features/full-graph/components/ForceGraph/FocusModeStyling.spec.ts
  • apps/eclair/src/features/full-graph/components/ForceGraph/ForceGraph.spec.tsx
  • apps/eclair/src/features/full-graph/components/ForceGraph/GraphRenderingSetup.setupZoomBehavior.spec.ts
  • apps/eclair/src/features/full-graph/components/ForceGraph/GraphRenderingSetup.spec.ts
  • apps/eclair/src/features/full-graph/components/ForceGraph/GraphRenderingSetup.updateHighlight.spec.ts
  • apps/eclair/src/features/full-graph/components/ForceGraph/VisualizationDataAdapters.spec.ts
  • apps/eclair/src/features/full-graph/components/ForceGraph/applyFocusModeBehavior.spec.ts
  • apps/eclair/src/features/full-graph/components/ForceGraph/computeDagreLayout.spec.ts
  • apps/eclair/src/features/full-graph/components/GraphSearch/GraphSearch.spec.tsx
  • apps/eclair/src/features/full-graph/components/GraphTooltip/GraphTooltip.spec.tsx
  • apps/eclair/src/features/full-graph/components/NodeTypeFilters/NodeTypeFilters.spec.tsx
  • apps/eclair/src/features/full-graph/graphFocusing/filterByNodeType.spec.ts
  • apps/eclair/src/features/full-graph/graphFocusing/focusModeConstants.spec.ts
  • apps/eclair/src/features/full-graph/graphFocusing/themeFocusColors.spec.ts
  • apps/eclair/src/features/full-graph/hooks/useFlowTracing.spec.ts
  • apps/eclair/src/features/full-graph/hooks/useNodeDepth.spec.ts
  • apps/eclair/src/features/full-graph/hooks/useNodeSearch.spec.ts
  • apps/eclair/src/features/full-graph/types.spec.ts
  • apps/eclair/src/features/overview/OverviewPage.displayLimits.spec.tsx
  • apps/eclair/src/features/overview/OverviewPage.spec.tsx
  • apps/eclair/src/lib/exportGraph.spec.ts
  • apps/eclair/src/lib/graphStats.spec.ts
  • apps/eclair/src/lib/handlePositioning.spec.ts
  • apps/eclair/src/test-assertions.ts
  • apps/eclair/vitest.browser.config.mts
  • eslint.config.mjs
  • package.json
  • packages/riviere-builder/src/builder-components.spec.ts
  • packages/riviere-builder/src/builder-custom-types.spec.ts
  • packages/riviere-builder/src/builder-export.spec.ts
  • packages/riviere-builder/src/builder-inspection.spec.ts
  • packages/riviere-builder/src/builder-links.spec.ts
  • packages/riviere-builder/src/builder-near-matches.spec.ts
  • packages/riviere-builder/src/builder-validation.spec.ts
  • packages/riviere-builder/src/builder.spec.ts
  • packages/riviere-builder/src/deduplicate.spec.ts
  • packages/riviere-builder/src/errors.spec.ts
  • packages/riviere-builder/src/merge-behavior.spec.ts
  • packages/riviere-cli/src/cli.spec.ts
  • packages/riviere-cli/src/command-test-fixtures.ts
  • packages/riviere-cli/src/commands/builder/component-summary.spec.ts
  • packages/riviere-cli/src/commands/builder/finalize.spec.ts
  • packages/riviere-cli/src/commands/builder/init-options.spec.ts
  • packages/riviere-cli/src/commands/builder/init.spec.ts
  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/src/commands/query/components.spec.ts
  • packages/riviere-cli/src/commands/query/domains.spec.ts
  • packages/riviere-cli/src/commands/query/load-graph.spec.ts
  • packages/riviere-cli/src/commands/query/orphans.spec.ts
  • packages/riviere-cli/src/commands/query/trace.spec.ts
  • packages/riviere-cli/src/component-types.spec.ts
  • packages/riviere-cli/src/output.spec.ts
  • packages/riviere-cli/src/validation.spec.ts
  • packages/riviere-extract-config/src/validation.spec.ts
  • packages/riviere-extract-conventions/src/decorators.spec.ts
  • packages/riviere-extract-conventions/src/default-config-fixtures.spec.ts
  • packages/riviere-extract-conventions/src/default-config.spec.ts
  • packages/riviere-extract-ts/src/extractor.spec.ts
  • packages/riviere-query/src/RiviereQuery.spec.ts
  • packages/riviere-query/src/RiviereQuery.validation.spec.ts
  • packages/riviere-query/src/cross-domain-links.spec.ts
  • packages/riviere-query/src/diff.spec.ts
  • packages/riviere-query/src/domain-connections.spec.ts
  • packages/riviere-query/src/domains.spec.ts
  • packages/riviere-query/src/entities.spec.ts
  • packages/riviere-query/src/errors.spec.ts
  • packages/riviere-query/src/events.spec.ts
  • packages/riviere-query/src/external-systems.spec.ts
  • packages/riviere-query/src/flows.spec.ts
  • packages/riviere-query/src/riviere-graph-fixtures.ts
  • packages/riviere-query/src/state-machine.spec.ts
  • packages/riviere-query/src/stats.spec.ts
  • packages/riviere-query/src/traceFlow.spec.ts
  • packages/riviere-schema/src/schema.spec.ts
📝 Walkthrough

Walkthrough

Adds a new riviere extract CLI command that reads and validates a YAML extraction config, resolves source files by globs, runs extraction via ts-morph and extractComponents, and emits JSON results or structured errors. Also updates CLI deps, TypeScript project refs, tests, and narrows an automation permission.

Changes

Cohort / File(s) Summary
Configuration & Automation
\.claude/settings.json
Removed allowed Bash execution entry for ./scripts/submit-pr.sh from the "allow" list.
Dependencies & Build Configuration
packages/riviere-cli/package.json, packages/riviere-cli/tsconfig.lib.json
Added engine (node>=20), workspace deps @living-architecture/riviere-extract-config, @living-architecture/riviere-extract-ts; added deps glob, ts-morph, yaml; updated TS project references to include extraction packages.
CLI Core
packages/riviere-cli/src/cli.ts, packages/riviere-cli/src/error-codes.ts
Registered new extract command via program.addCommand(createExtractCommand()); added ConfigNotFound = 'CONFIG_NOT_FOUND' to CliErrorCode.
Extract Command Implementation
packages/riviere-cli/src/commands/extract/extract.ts
New exported createExtractCommand() implementing --config handling, YAML parse, schema validation, glob resolution, ts-morph project creation, and calling extractComponents; formats JSON success/errors.
Tests & Fixtures
packages/riviere-cli/src/commands/extract/extract.spec.ts, packages/riviere-cli/src/command-test-fixtures.ts
Added Vitest tests covering missing/invalid config, validation errors, no-match globs, and successful extraction output; introduced ProcessExitError and test exit mocking.
Docs Generation
packages/riviere-cli/scripts/generate-docs.ts
Include "Extract Commands" in generated CLI reference and usage snippets.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI as riviere extract
    participant FS as File System
    participant Parser as YAML/Schema Validator
    participant Globber as Glob Resolver
    participant TSMorph as ts-morph Project
    participant Extractor as extractComponents
    participant Out as STDOUT (JSON)

    User->>CLI: riviere extract --config config.yaml
    CLI->>FS: stat config.yaml
    alt not found
        CLI->>Out: emit error { code: CONFIG_NOT_FOUND, ... }
    else found
        CLI->>FS: read config.yaml
        CLI->>Parser: parse & validate YAML
        alt parse/validation error
            CLI->>Out: emit error { code: VALIDATION_ERROR, details }
        else valid
            CLI->>Globber: resolve module globs (relative to config dir)
            Globber->>FS: match file paths
            Globber->>CLI: matched paths
            CLI->>TSMorph: create Project & add files
            CLI->>Extractor: extractComponents(project, paths, config)
            Extractor->>CLI: components[]
            CLI->>Out: emit success { success: true, data: components }
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Possibly related PRs

Poem

🐰
I nibble configs, YAML bright and neat,
Globs I chase with tiny hopping feet,
ts-morph hums as I sift the code,
JSON carrots tumble down the road,
Hooray—extraction treats for every fleet!

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(riviere-cli): add extract command for component extraction' accurately summarizes the main change: adding a new extract command to the riviere-cli package.
Linked Issues check ✅ Passed The PR implements all coding requirements from issue #44: the extract command with --config option, YAML config validation with ConfigNotFound error, glob-based file resolution, ts-morph component extraction, JSON output, and comprehensive integration tests.
Out of Scope Changes check ✅ Passed All changes align with the PR objectives: extract command implementation, config handling, dependency additions, documentation generation, and test infrastructure changes for proper error handling are all within scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jan 9, 2026 •

Copy link
Copy Markdown

Deploying living-architecture with  Cloudflare Pages  Cloudflare Pages

Latest commit: 2c9255f
Status: ✅  Deploy successful!
Preview URL: https://f3d12ef6.living-architecture.pages.dev
Branch Preview URL: https://issue-44-m4-d4-1-add-riviere.living-architecture.pages.dev

View logs

@qodo-code-review

qodo-code-review Bot commented Jan 9, 2026 •

Copy link
Copy Markdown
Contributor

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
⚪
Path-based file read

Description: The command reads an arbitrary user-supplied config path and expands config-controlled
glob patterns into absolute paths, potentially allowing a malicious config to cause
unintended local file enumeration/reads (e.g., path: "../../**/*"), which could expose
sensitive files in CI logs/artifacts if the config source is untrusted.
extract.ts [55-104]

Referred Code
if (!existsSync(options.config)) {
  console.log(
    JSON.stringify(
      formatError(CliErrorCode.ConfigNotFound, `Config file not found: ${options.config}`),
    ),
  )
  return
}

const content = readFileSync(options.config, 'utf-8')
const parseResult = parseConfigFile(content)

if (!parseResult.success) {
  console.log(
    JSON.stringify(
      formatError(CliErrorCode.ValidationError, `Invalid config file: ${parseResult.error}`),
    ),
  )
  return
}



 ... (clipped 29 lines)
Ticket Compliance
🟢
🎫 #44
🟢 Add a new CLI command `riviere extract --config ` to run component extraction.
With a valid extraction config, running riviere extract --config ./extraction.config.yaml
outputs draft components JSON to stdout.
With a missing config file, the command returns a clear error message indicating the file
was not found.
With an invalid config file, validation errors are reported with helpful details.
When extraction completes, captured output is valid JSON parseable by other tools.
Provide verification via nx test riviere-cli and nx build riviere-cli, including CLI
integration tests covering valid/invalid configs.
Codebase Duplication Compliance
⚪
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Unhandled exceptions: The command does not catch/handle failures from readFileSync, globSync,
project.addSourceFileAtPath, or extractComponents, which can crash the CLI and prevent
returning a structured error response.

Referred Code
const content = readFileSync(options.config, 'utf-8')
const parseResult = parseConfigFile(content)

if (!parseResult.success) {
  console.log(
    JSON.stringify(
      formatError(CliErrorCode.ValidationError, `Invalid config file: ${parseResult.error}`),
    ),
  )
  return
}

if (!isValidExtractionConfig(parseResult.data)) {
  const validationResult = validateExtractionConfig(parseResult.data)
  console.log(
    JSON.stringify(
      formatError(
        CliErrorCode.ValidationError,
        `Invalid extraction config:\n${formatValidationErrors(validationResult.errors)}`,
      ),
    ),


 ... (clipped 19 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status:
Stack trace exposure: Because runtime errors from filesystem access, globbing, ts-morph project building, or
extraction are not caught, the CLI may expose raw stack traces and internal details
directly to the end-user.

Referred Code
const content = readFileSync(options.config, 'utf-8')
const parseResult = parseConfigFile(content)

if (!parseResult.success) {
  console.log(
    JSON.stringify(
      formatError(CliErrorCode.ValidationError, `Invalid config file: ${parseResult.error}`),
    ),
  )
  return
}

if (!isValidExtractionConfig(parseResult.data)) {
  const validationResult = validateExtractionConfig(parseResult.data)
  console.log(
    JSON.stringify(
      formatError(
        CliErrorCode.ValidationError,
        `Invalid extraction config:\n${formatValidationErrors(validationResult.errors)}`,
      ),
    ),


 ... (clipped 19 lines)

Learn more about managing compliance generic rules or creating your own custom rules

⚪
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
No audit trail: The new extract command performs filesystem reads and code extraction without emitting any
audit log entries containing user identity, timestamp, action, and outcome, so whether
this is acceptable depends on whether CLI executions are considered "critical
actions" in this product context.

Referred Code
.action((options: ExtractOptions) => {
  if (!existsSync(options.config)) {
    console.log(
      JSON.stringify(
        formatError(CliErrorCode.ConfigNotFound, `Config file not found: ${options.config}`),
      ),
    )
    return
  }

  const content = readFileSync(options.config, 'utf-8')
  const parseResult = parseConfigFile(content)

  if (!parseResult.success) {
    console.log(
      JSON.stringify(
        formatError(CliErrorCode.ValidationError, `Invalid config file: ${parseResult.error}`),
      ),
    )
    return
  }


 ... (clipped 30 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Sensitive output risk: The command prints extracted component data and validation error details to stdout via
console.log(JSON.stringify(...)), which could unintentionally disclose sensitive
identifiers/paths depending on where stdout is collected (CI logs, centralized logging,
etc.).

Referred Code
  console.log(
    JSON.stringify(
      formatError(CliErrorCode.ConfigNotFound, `Config file not found: ${options.config}`),
    ),
  )
  return
}

const content = readFileSync(options.config, 'utf-8')
const parseResult = parseConfigFile(content)

if (!parseResult.success) {
  console.log(
    JSON.stringify(
      formatError(CliErrorCode.ValidationError, `Invalid config file: ${parseResult.error}`),
    ),
  )
  return
}

if (!isValidExtractionConfig(parseResult.data)) {


 ... (clipped 27 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Unrestricted path patterns: The implementation resolves and glob-expands file patterns from a user-provided YAML
config (config.modules[].path) and then loads those files into a ts-morph Project without
explicit restrictions/allowlisting, which may be acceptable for a local CLI but should be
confirmed against the threat model.

Referred Code
const config = parseResult.data
const configDir = dirname(resolve(options.config))

const sourceFilePaths = config.modules
  .flatMap((module) => globSync(module.path, { cwd: configDir }))
  .map((filePath) => resolve(configDir, filePath))

const project = new Project()
for (const filePath of sourceFilePaths) {
  project.addSourceFileAtPath(filePath)
}

const components = extractComponents(project, sourceFilePaths, config)

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review

qodo-code-review Bot commented Jan 9, 2026 •

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Encapsulate ts-morph logic within extraction package

Move the creation and population of the ts-morph Project instance from the
riviere-cli package into the @living-architecture/riviere-extract-ts package.
This change decouples the CLI from the extraction library's implementation
details.

Examples:

packages/riviere-cli/src/commands/extract/extract.ts [96-101]
      const project = new Project()
      for (const filePath of sourceFilePaths) {
        project.addSourceFileAtPath(filePath)
      }

      const components = extractComponents(project, sourceFilePaths, config)

Solution Walkthrough:

Before:

// packages/riviere-cli/src/commands/extract/extract.ts
import { Project } from 'ts-morph';
import { extractComponents } from '@living-architecture/riviere-extract-ts';

function createExtractCommand(): Command {
  // ...
  .action((options: ExtractOptions) => {
    // ...
    const sourceFilePaths = globSync(...);

    const project = new Project();
    project.addSourceFilesAtPaths(sourceFilePaths);

    const components = extractComponents(project, sourceFilePaths, config);
    console.log(JSON.stringify(formatSuccess(components)));
  });
}

After:

// packages/riviere-cli/src/commands/extract/extract.ts
// No import from 'ts-morph'
import { extractComponents } from '@living-architecture/riviere-extract-ts';

function createExtractCommand(): Command {
  // ...
  .action((options: ExtractOptions) => {
    // ...
    const sourceFilePaths = globSync(...);

    // Project creation is now handled within extractComponents
    const components = extractComponents(sourceFilePaths, config);
    console.log(JSON.stringify(formatSuccess(components)));
  });
}

// --- In @living-architecture/riviere-extract-ts ---
// export function extractComponents(sourceFilePaths, config) {
//   const project = new Project();
//   ...
// }
Suggestion importance[1-10]: 7

__

Why: This is a strong architectural suggestion that correctly identifies a tight coupling and proposes a change that improves modularity and separation of concerns between packages.

Medium
Possible issue
Add error handling for file read

Wrap the readFileSync call in a try...catch block to handle potential file read
errors, such as permission issues or race conditions, and prevent the CLI from
crashing.

packages/riviere-cli/src/commands/extract/extract.ts [54-104]

 .action((options: ExtractOptions) => {
   if (!existsSync(options.config)) {
     console.log(
       JSON.stringify(
         formatError(CliErrorCode.ConfigNotFound, `Config file not found: ${options.config}`),
       ),
     )
     return
   }
 
-  const content = readFileSync(options.config, 'utf-8')
+  let content: string
+  try {
+    content = readFileSync(options.config, 'utf-8')
+  } catch (error) {
+    const message = error instanceof Error ? error.message : 'Unknown read error'
+    console.log(
+      JSON.stringify(formatError(CliErrorCode.ValidationError, `Could not read config file: ${message}`)),
+    )
+    return
+  }
+
   const parseResult = parseConfigFile(content)
   ...
 })

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 7

__

Why: This suggestion correctly identifies a potential unhandled exception if readFileSync fails due to permissions or a race condition, and proposes a try...catch block that improves the CLI's robustness by preventing a crash.

Medium
General
✅ Handle no source files
Suggestion Impact:The commit adds a guard for an empty sourceFilePaths array, printing a ValidationError message including the patterns and configDir, and returning early to avoid proceeding with extraction. (It does not set a non-zero exit code as suggested.)

code diff:

+      if (sourceFilePaths.length === 0) {
+        const patterns = config.modules.map((m) => m.path).join(', ')
+        console.log(
+          JSON.stringify(
+            formatError(
+              CliErrorCode.ValidationError,
+              `No files matched extraction patterns: ${patterns}\nConfig directory: ${configDir}`,
+            ),
+          ),
+        )
+        return
+      }

Add a check to ensure sourceFilePaths is not empty after globbing. If no files
are found, output an error and exit with a non-zero status code.

packages/riviere-cli/src/commands/extract/extract.ts [92-94]

 const sourceFilePaths = config.modules
   .flatMap((module) => globSync(module.path, { cwd: configDir }))
   .map((filePath) => resolve(configDir, filePath))
+if (sourceFilePaths.length === 0) {
+  console.log(JSON.stringify(formatError(CliErrorCode.ValidationError, `No source files found for patterns: ${config.modules.map(m => m.path).join(', ')}`)))
+  process.exitCode = 1
+  return
+}

[Suggestion processed]

Suggestion importance[1-10]: 7

__

Why: This suggestion correctly identifies a missing edge case where no source files are found, preventing the tool from proceeding with an empty file list. Adding this check improves robustness and provides clearer user feedback.

Medium
✅ Set exit code on error
Suggestion Impact:The commit updated error-handling branches to terminate the process with a non-zero status (using process.exit(1)) after logging formatted errors, addressing the suggestion’s goal of signaling failure to the shell/scripts.

code diff:

@@ -58,7 +58,7 @@
             formatError(CliErrorCode.ConfigNotFound, `Config file not found: ${options.config}`),
           ),
         )
-        return
+        process.exit(1)
       }
 
       const content = readFileSync(options.config, 'utf-8')
@@ -70,7 +70,7 @@
             formatError(CliErrorCode.ValidationError, `Invalid config file: ${parseResult.error}`),
           ),
         )
-        return
+        process.exit(1)
       }
 
       if (!isValidExtractionConfig(parseResult.data)) {
@@ -83,7 +83,7 @@
             ),
           ),
         )
-        return
+        process.exit(1)
       }

Set process.exitCode = 1 after printing an error message to ensure the CLI
process exits with a non-zero status code, indicating failure.

packages/riviere-cli/src/commands/extract/extract.ts [55-62]

 if (!existsSync(options.config)) {
-  console.log(
-    JSON.stringify(
-      formatError(CliErrorCode.ConfigNotFound, `Config file not found: ${options.config}`),
-    ),
-  )
+  console.log(JSON.stringify(formatError(CliErrorCode.ConfigNotFound, `Config file not found: ${options.config}`)))
+  process.exitCode = 1
   return
 }

[Suggestion processed]

Suggestion importance[1-10]: 6

__

Why: This suggestion correctly identifies that the CLI does not exit with a non-zero status code on failure, which is a standard practice for command-line tools. Implementing this improves integration with scripting and automated workflows.

Low
Avoid redundant config validation call

Avoid a redundant validation call by invoking validateExtractionConfig only
once, storing its result, and then checking the result to improve efficiency.

packages/riviere-cli/src/commands/extract/extract.ts [76-87]

-if (!isValidExtractionConfig(parseResult.data)) {
-  const validationResult = validateExtractionConfig(parseResult.data)
+const validationResult = validateExtractionConfig(parseResult.data)
+if (!validationResult.valid) {
   console.log(
     JSON.stringify(
       formatError(
         CliErrorCode.ValidationError,
         `Invalid extraction config:\n${formatValidationErrors(validationResult.errors)}`,
       ),
     ),
   )
   return
 }
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why: The suggestion correctly points out a redundant function call and proposes a more efficient approach by calling the validation function only once. This is a good optimization for code quality and performance.

Low
Simplify file path resolution logic

Simplify file path resolution by using the absolute: true option in globSync to
get absolute paths directly, removing the need for a separate .map() call with
resolve().

packages/riviere-cli/src/commands/extract/extract.ts [92-94]

-const sourceFilePaths = config.modules
-  .flatMap((module) => globSync(module.path, { cwd: configDir }))
-  .map((filePath) => resolve(configDir, filePath))
+const sourceFilePaths = config.modules.flatMap((module) =>
+  globSync(module.path, { cwd: configDir, absolute: true }),
+)
  • Apply / Chat
Suggestion importance[1-10]: 4

__

Why: This is a valid suggestion that simplifies the code by using the absolute: true option in globSync, making the file path resolution more concise and idiomatic.

Low
  • Update

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Fix all issues with AI agents
In @packages/riviere-cli/package.json:
- Around line 29-36: The package.json is missing an "engines" declaration to
require Node.js 20+, causing installs on older Node versions to succeed despite
dependencies (commander and glob) needing Node 20; add an "engines" field in
package.json with "node": ">=20" so package managers and CI enforce the minimum
Node version, ensuring compatibility with the listed dependencies.

In @packages/riviere-cli/src/cli.ts:
- Line 23: The docs generator is excluding the top-level "extract" command
because generate-docs.ts only keeps commands whose fullName startsWith('riviere
builder') or startsWith('riviere query'), so ensure the filter includes the
extract command (whose command is wired via createExtractCommand / registered as
'extract') by adding startsWith('riviere extract') or by changing the filter
logic to include non-subcommands; also address missing workflow prompt
references by creating the referenced docs/workflow/step-1 .. step-6 files or
removing/updating the learnings entries to point to existing workflow docs so
generated documentation no longer references nonexistent files.

In @packages/riviere-cli/src/commands/extract/extract.spec.ts:
- Around line 1-47: The type guard is too permissive and parseExtractionOutput
assumes the JSON is on consoleOutput[0]; tighten isExtractionOutput to validate
each DraftComponent (at least check that data[0] has type, name, domain and
location.file and location.line) and update parseExtractionOutput to locate and
JSON.parse the first line that looks like JSON (not just index 0) before passing
it to isExtractionOutput; reference the DraftComponent and ExtractionOutput
shapes, the isExtractionOutput function, and parseExtractionOutput when making
these checks and the scanning change.

In @packages/riviere-cli/src/commands/extract/extract.ts:
- Around line 67-74: Add a distinct ParseError variant to the CliErrorCode enum
and use it when parseResult indicates a YAML syntax/parsing failure: update the
enum (CliErrorCode) to include ParseError, detect parse vs schema errors in the
parsing flow (the parseResult object returned where parseResult.success is
false), and call formatError(CliErrorCode.ParseError, ...) for malformed YAML
while retaining formatError(CliErrorCode.ValidationError, ...) for schema
validation failures so logs and error consumers can distinguish the two cases.
- Around line 89-94: After resolving config (config) and computing
sourceFilePaths from config.modules, add a validation that sourceFilePaths is
not empty: if sourceFilePaths.length === 0, fail fast with a clear, actionable
error message that indicates no files matched the provided glob patterns from
config.modules and include the resolved config path (configDir) or the offending
module pattern(s) so the user can correct the extraction config; perform this
check immediately after the existing sourceFilePaths assignment and throw or
return an error/exit with a non-zero status to stop silent zero-component
output.
- Around line 55-62: The action handler currently logs config/missing-file
errors (e.g., the existsSync check using options.config and formatError with
CliErrorCode.ConfigNotFound) and returns, which leaves the process exit code as
zero; replace those early returns with throwing an Error (or calling
process.exit(1)) so the CLI fails in CI. Concretely, in the block that logs the
config-not-found error and in the other error-paths (the blocks around the
checks at lines ~68-73 and ~78-86), either throw a descriptive Error (including
the same formatted message) or invoke process.exit(1) immediately after logging;
ensure you update all referenced spots (options.config check, the other
validation branches) so every error path results in a non-zero exit/failure
signal.
- Around line 96-99: The current loop creates a Project and calls
Project.addSourceFileAtPath for each path; replace this with a single call to
Project.addSourceFilesAtPaths(sourceFilePaths) to add files in batch (use the
same Project constructor), remove any unnecessary tsconfig loading since default
compiler options suffice for AST extraction, and delete the for-loop that
iterates over sourceFilePaths while keeping the Project instantiation and
subsequent usage intact.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d749d63 and cee47ce.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (7)
  • .claude/settings.json
  • packages/riviere-cli/package.json
  • packages/riviere-cli/src/cli.ts
  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/src/commands/extract/extract.ts
  • packages/riviere-cli/src/error-codes.ts
  • packages/riviere-cli/tsconfig.lib.json
💤 Files with no reviewable changes (1)
  • .claude/settings.json
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: When writing, editing, refactoring, or reviewing code, always follow docs/conventions/software-design.md
Look for standard implementation patterns defined in docs/conventions/standard-patterns.md
Avoid anti-patterns defined in @docs/conventions/anti-patterns.md
100% test coverage is mandatory and enforced
Use domain terminology from docs/architecture/domain-terminology/contextive/definitions.glossary.yml. Do not invent new terms or use technical jargon when domain terminology exists
Never commit secrets, API keys, or credentials. Use environment variables for sensitive configuration. Do not log sensitive data (passwords, tokens, PII). Validate and sanitize all external input

Files:

  • packages/riviere-cli/src/error-codes.ts
  • packages/riviere-cli/src/commands/extract/extract.ts
  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/src/cli.ts
**/*.{ts,tsx,js,jsx,json,css,scss}

📄 CodeRabbit inference engine (CLAUDE.md)

All UI and UX design must conform to global brand guidelines: /docs/brand/ (logo, colors, typography, icons)

Files:

  • packages/riviere-cli/src/error-codes.ts
  • packages/riviere-cli/package.json
  • packages/riviere-cli/src/commands/extract/extract.ts
  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/tsconfig.lib.json
  • packages/riviere-cli/src/cli.ts
packages/**

📄 CodeRabbit inference engine (CLAUDE.md)

Create new shared libraries as publishable packages in the packages/ directory using pnpm nx g @nx/js:library packages/[pkg-name] --publishable --importPath=@living-architecture/[pkg-name]

Files:

  • packages/riviere-cli/src/error-codes.ts
  • packages/riviere-cli/package.json
  • packages/riviere-cli/src/commands/extract/extract.ts
  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/tsconfig.lib.json
  • packages/riviere-cli/src/cli.ts
**/*.json

📄 CodeRabbit inference engine (CLAUDE.md)

After generating a new project, update the project's package.json with correct name: @living-architecture/[project-name]

Files:

  • packages/riviere-cli/package.json
  • packages/riviere-cli/tsconfig.lib.json
**/*.spec.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Follow docs/conventions/testing.md for all test files

Files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
🧠 Learnings (24)
📓 Common learnings
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.test.{ts,tsx} : Implement integration tests for end-to-end extraction from TypeScript code to JSON output
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/architecture/overview.md:0-0
Timestamp: 2026-01-08T22:20:13.250Z
Learning: Applies to docs/architecture/**/*extract*.ts : Use `living-architecture/riviere-extract-ts` TypeScript extractor with ts-morph for AST parsing when implementing TypeScript extraction for architecture schema components
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/architecture/overview.md:0-0
Timestamp: 2026-01-08T22:20:13.250Z
Learning: Applies to docs/architecture/**/*extract*.{json,ts} : Define extraction configuration using the JSON Schema from `living-architecture/riviere-extract-config` DSL
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.{ts,tsx} : Implement extraction logic as pure functions with no side effects
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-conventions/CLAUDE.md:0-0
Timestamp: 2026-01-08T07:05:01.766Z
Learning: Import and use the default extraction config from `living-architecture/riviere-extract-conventions/default-config` in extraction tooling to detect all 6 component types
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/architecture/overview.md:0-0
Timestamp: 2026-01-08T22:20:13.250Z
Learning: Applies to docs/architecture/**/*extract*.ts : Use the Rivière Builder Node.js library to programmatically construct the schema graph when implementing custom extraction code
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-config/CLAUDE.md:0-0
Timestamp: 2026-01-06T23:01:34.751Z
Learning: Applies to packages/riviere-extract-config/**/*.ts : Extraction config schema is the source of truth for valid structures. TypeScript types must mirror the schema definition to maintain consistency
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.{ts,tsx} : Reject invalid extraction configs at load time, not during extraction phase
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.{ts,tsx} : Use glob pattern matching for module-based organization of extraction rules
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-cli/CLAUDE.md:0-0
Timestamp: 2026-01-02T11:58:27.018Z
Learning: When modifying CLI commands in the riviere-cli tool, update the corresponding workflow prompts in docs/workflow/ directory (step-1 through step-6) to keep the extraction workflow in sync
📚 Learning: 2026-01-06T23:01:34.751Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-config/CLAUDE.md:0-0
Timestamp: 2026-01-06T23:01:34.751Z
Learning: Applies to packages/riviere-extract-config/**/*.ts : Extraction config schema is the source of truth for valid structures. TypeScript types must mirror the schema definition to maintain consistency

Applied to files:

  • packages/riviere-cli/src/error-codes.ts
  • packages/riviere-cli/package.json
  • packages/riviere-cli/src/commands/extract/extract.ts
  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/tsconfig.lib.json
📚 Learning: 2026-01-08T17:19:17.148Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.{ts,tsx} : Use ts-morph for TypeScript AST parsing instead of other parsers

Applied to files:

  • packages/riviere-cli/package.json
  • packages/riviere-cli/src/commands/extract/extract.ts
  • packages/riviere-cli/tsconfig.lib.json
  • packages/riviere-cli/src/cli.ts
📚 Learning: 2026-01-08T19:36:17.306Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/conventions/codebase-structure.md:0-0
Timestamp: 2026-01-08T19:36:17.306Z
Learning: Applies to docs/conventions/packages/*/package.json : When importing from another project, add explicit workspace dependencies to package.json using the format "living-architecture/[pkg-name]": "workspace:*" and run pnpm install.

Applied to files:

  • packages/riviere-cli/package.json
📚 Learning: 2026-01-08T19:36:17.306Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/conventions/codebase-structure.md:0-0
Timestamp: 2026-01-08T19:36:17.306Z
Learning: Applies to docs/conventions/apps/*/package.json : When importing from another project, add explicit workspace dependencies to package.json using the format "living-architecture/[pkg-name]": "workspace:*" and run pnpm install.

Applied to files:

  • packages/riviere-cli/package.json
📚 Learning: 2026-01-08T17:19:17.148Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.{ts,tsx} : Implement extraction logic as pure functions with no side effects

Applied to files:

  • packages/riviere-cli/package.json
  • packages/riviere-cli/src/commands/extract/extract.ts
  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/tsconfig.lib.json
  • packages/riviere-cli/src/cli.ts
📚 Learning: 2026-01-08T17:19:17.148Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.{ts,tsx} : Use glob pattern matching for module-based organization of extraction rules

Applied to files:

  • packages/riviere-cli/package.json
  • packages/riviere-cli/src/commands/extract/extract.ts
  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/tsconfig.lib.json
  • packages/riviere-cli/src/cli.ts
📚 Learning: 2026-01-08T17:19:17.148Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.test.{ts,tsx} : Implement integration tests for end-to-end extraction from TypeScript code to JSON output

Applied to files:

  • packages/riviere-cli/package.json
  • packages/riviere-cli/src/commands/extract/extract.ts
  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/tsconfig.lib.json
  • packages/riviere-cli/src/cli.ts
📚 Learning: 2026-01-08T22:20:13.250Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/architecture/overview.md:0-0
Timestamp: 2026-01-08T22:20:13.250Z
Learning: Applies to docs/architecture/**/*extract*.ts : Use `living-architecture/riviere-extract-ts` TypeScript extractor with ts-morph for AST parsing when implementing TypeScript extraction for architecture schema components

Applied to files:

  • packages/riviere-cli/package.json
  • packages/riviere-cli/src/commands/extract/extract.ts
  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/tsconfig.lib.json
  • packages/riviere-cli/src/cli.ts
📚 Learning: 2026-01-08T17:19:17.148Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.test.{ts,tsx} : Use ts-morph's in-memory file system (`useInMemoryFileSystem: true`) for fast isolated tests

Applied to files:

  • packages/riviere-cli/package.json
  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/tsconfig.lib.json
📚 Learning: 2026-01-02T11:58:27.018Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-cli/CLAUDE.md:0-0
Timestamp: 2026-01-02T11:58:27.018Z
Learning: When modifying CLI commands in the riviere-cli tool, update the corresponding workflow prompts in docs/workflow/ directory (step-1 through step-6) to keep the extraction workflow in sync

Applied to files:

  • packages/riviere-cli/package.json
  • packages/riviere-cli/src/cli.ts
📚 Learning: 2026-01-08T22:20:13.250Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/architecture/overview.md:0-0
Timestamp: 2026-01-08T22:20:13.250Z
Learning: Applies to docs/architecture/**/*extract*.{json,ts} : Define extraction configuration using the JSON Schema from `living-architecture/riviere-extract-config` DSL

Applied to files:

  • packages/riviere-cli/package.json
  • packages/riviere-cli/src/commands/extract/extract.ts
  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/tsconfig.lib.json
  • packages/riviere-cli/src/cli.ts
📚 Learning: 2026-01-08T22:20:13.250Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/architecture/overview.md:0-0
Timestamp: 2026-01-08T22:20:13.250Z
Learning: Applies to docs/architecture/**/*extract*.ts : Use the Rivière Builder Node.js library to programmatically construct the schema graph when implementing custom extraction code

Applied to files:

  • packages/riviere-cli/package.json
  • packages/riviere-cli/src/commands/extract/extract.ts
  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/tsconfig.lib.json
  • packages/riviere-cli/src/cli.ts
📚 Learning: 2026-01-08T22:20:13.250Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/architecture/overview.md:0-0
Timestamp: 2026-01-08T22:20:13.250Z
Learning: Applies to docs/architecture/**/*.{ts,tsx} : Apply decorators from `living-architecture/riviere-extract-conventions` to mark all classes as architectural components

Applied to files:

  • packages/riviere-cli/package.json
  • packages/riviere-cli/src/commands/extract/extract.ts
📚 Learning: 2026-01-08T07:05:01.766Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-conventions/CLAUDE.md:0-0
Timestamp: 2026-01-08T07:05:01.766Z
Learning: Import and use the default extraction config from `living-architecture/riviere-extract-conventions/default-config` in extraction tooling to detect all 6 component types

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.ts
  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/src/cli.ts
📚 Learning: 2026-01-08T17:19:17.148Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.{ts,tsx} : Reject invalid extraction configs at load time, not during extraction phase

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.ts
  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/tsconfig.lib.json
  • packages/riviere-cli/src/cli.ts
📚 Learning: 2026-01-08T17:19:17.148Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: All extraction rules should come from validated ExtractionConfig provided by riviere-extract-config

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.ts
📚 Learning: 2026-01-08T17:19:17.148Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.test.{ts,tsx} : Implement unit tests for each predicate type in isolation with positive and negative cases

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
📚 Learning: 2026-01-08T17:19:17.148Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/vitest.config.mts : Enforce 100% code coverage using Vitest with v8 coverage and thresholds configured in vitest.config.mts

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
📚 Learning: 2026-01-08T06:46:00.609Z
Learnt from: NTCoding
Repo: NTCoding/living-architecture PR: 66
File: packages/riviere-extract-conventions/src/eslint/require-component-decorator.spec.ts:19-21
Timestamp: 2026-01-08T06:46:00.609Z
Learning: In test files using typescript-eslint/rule-tester's RuleTester.run(), ensure there is an explicit it() block with at least one expect() assertion (e.g., expect(rule).toBeDefined()) to satisfy sonarjs/no-empty-test-file and sonarjs/assertions-in-tests lint rules, which don’t recognize RuleTester's internal test blocks. Apply this pattern to all spec.ts test files to maintain consistency and pass lint checks.

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
📚 Learning: 2026-01-08T19:36:17.306Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/conventions/codebase-structure.md:0-0
Timestamp: 2026-01-08T19:36:17.306Z
Learning: Applies to docs/conventions/packages/*/tsconfig.lib.json : The tsconfig.lib.json file must extend tsconfig.base.json, set outDir to ./dist, rootDir to ./src, and include only src/**/*.ts while excluding src/**/*.test.ts files.

Applied to files:

  • packages/riviere-cli/tsconfig.lib.json
📚 Learning: 2026-01-08T19:36:17.306Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/conventions/codebase-structure.md:0-0
Timestamp: 2026-01-08T19:36:17.306Z
Learning: Applies to docs/conventions/apps/*/tsconfig.lib.json : The tsconfig.lib.json file must extend tsconfig.base.json, set outDir to ./dist, rootDir to ./src, and include only src/**/*.ts while excluding src/**/*.test.ts files.

Applied to files:

  • packages/riviere-cli/tsconfig.lib.json
📚 Learning: 2026-01-08T12:57:19.167Z
Learnt from: NTCoding
Repo: NTCoding/living-architecture PR: 67
File: packages/riviere-extract-ts/tsconfig.spec.json:5-22
Timestamp: 2026-01-08T12:57:19.167Z
Learning: In tsconfig.spec.json files, use expanded types array ["vitest/globals", "vitest/importMeta", "vite/client", "node", "vitest"] for complete test type coverage. Include patterns should cover .test and .spec files, config files (vitest.config.ts/mts, vite.config.ts/mts), multiple extensions (.ts, .tsx, .js, .jsx), and .d.ts files to ensure proper TypeScript coverage across the testing environment.

Applied to files:

  • packages/riviere-cli/tsconfig.lib.json
📚 Learning: 2026-01-02T11:58:27.018Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-cli/CLAUDE.md:0-0
Timestamp: 2026-01-02T11:58:27.018Z
Learning: After modifying CLI commands, run `nx generate-docs riviere-cli` to regenerate CLI reference documentation

Applied to files:

  • packages/riviere-cli/src/cli.ts
🧬 Code graph analysis (2)
packages/riviere-cli/src/commands/extract/extract.spec.ts (2)
packages/riviere-cli/src/cli.ts (1)
  • createProgram (44-78)
packages/riviere-cli/src/command-test-fixtures.ts (4)
  • TestContext (55-59)
  • createTestContext (61-67)
  • setupCommandTest (69-83)
  • parseErrorOutput (27-37)
packages/riviere-cli/src/cli.ts (1)
packages/riviere-cli/src/commands/extract/extract.ts (1)
  • createExtractCommand (50-105)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: browser-tests (chromium)
  • GitHub Check: main
  • GitHub Check: browser-tests (firefox)
  • GitHub Check: browser-tests (webkit)
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (11)
packages/riviere-cli/src/error-codes.ts (1)

14-14: Good addition; keeps CLI error taxonomy explicit.
CONFIG_NOT_FOUND is a clear, actionable code for the missing config scenario.

packages/riviere-cli/tsconfig.lib.json (1)

14-25: Project references look consistent with repo tsconfig conventions—please confirm intended build graph.
The updated references align with the new extract feature’s package dependencies; just ensure these projects are meant to participate in tsc -b for the CLI package (not only in tests). Based on learnings, tsconfig.lib.json structure looks correct.

packages/riviere-cli/src/commands/extract/extract.spec.ts (3)

49-56: Command registration test is solid.
Directly asserts the command exists at the top level (matches the desired UX).


58-99: Error-path coverage is good; consider also asserting CI-friendly exit behavior (if required).
You validate missing file and invalid config inputs well. If CI usage expects non-zero exit codes on failure, add an assertion around process.exitCode (or assert the command rejects/throws)—right now errors are “successful runs” from the process perspective.


101-150: Success-path test is good; make the YAML config minimal to reduce brittleness.
The { notUsed: true } fields risk turning into schema-invalid values if the extraction config schema becomes stricter; prefer omitting unused component types (or using the schema’s official “disable” mechanism, if any).

Proposed diff
       await writeFile(
         configPath,
         `
 modules:
   - name: orders
     path: "**/src/**/*.ts"
-    api: { notUsed: true }
     useCase:
       find: classes
       where:
         hasJSDoc:
           tag: useCase
-    domainOp: { notUsed: true }
-    event: { notUsed: true }
-    eventHandler: { notUsed: true }
-    ui: { notUsed: true }
 `,
       )
⛔ Skipped due to learnings
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-config/CLAUDE.md:0-0
Timestamp: 2026-01-06T23:01:34.751Z
Learning: Extraction config schemas must define all six required component types per module: api, useCase, domainOp, event, eventHandler, and ui. Unused component types must be explicitly marked with `notUsed: true` rather than omitted
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/architecture/overview.md:0-0
Timestamp: 2026-01-08T22:20:13.250Z
Learning: Applies to docs/architecture/**/*extract*.{json,ts} : Define extraction configuration using the JSON Schema from `living-architecture/riviere-extract-config` DSL
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/workflow/code-review.md:0-0
Timestamp: 2026-01-07T08:54:48.071Z
Learning: Applies to docs/workflow/**/*.{ts,tsx,js,jsx} : Review usage of `/* v8 ignore next -- preserve */` coverage skip directives. This is only acceptable for unreachable code needed to satisfy the compiler. Most cases should be solved by extracting code or writing tests to mock behavior.
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-config/CLAUDE.md:0-0
Timestamp: 2026-01-06T23:01:34.751Z
Learning: Applies to packages/riviere-extract-config/**/*.ts : Extraction config schema is the source of truth for valid structures. TypeScript types must mirror the schema definition to maintain consistency
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-09T18:58:21.008Z
Learning: Applies to **/*.config.ts : Add vitest.config.ts if tests are needed with 100% coverage as the default
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.{ts,tsx} : Reject invalid extraction configs at load time, not during extraction phase
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/workflow/code-review.md:0-0
Timestamp: 2026-01-07T08:54:48.071Z
Learning: Applies to docs/workflow/**/*.{ts,tsx,js,jsx,!(**/*.test.ts,**/*.test.tsx,**/*.test.js,**/*.spec.ts,**/*.spec.tsx,**/*.spec.js)} : Organize code by usage (vertical slice organization), not by type. Avoid folders/files named: types/, models/, validators/, assertions/, schemas/, interfaces/, or files like types.ts, models.ts, validators.ts. Group items by what uses them together, not by category.
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/architecture/overview.md:0-0
Timestamp: 2026-01-08T22:20:13.250Z
Learning: Applies to docs/architecture/**/*extract*.ts : Use `living-architecture/riviere-extract-ts` TypeScript extractor with ts-morph for AST parsing when implementing TypeScript extraction for architecture schema components
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/conventions/software-design.md:0-0
Timestamp: 2026-01-08T23:16:02.639Z
Learning: Applies to docs/conventions/**/*.{ts,tsx} : Parse, don't validate. Use Zod schemas at system boundaries to parse external data once. Don't scatter `isX(unknown): x is T` type guards throughout the codebase.
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/conventions/software-design.md:0-0
Timestamp: 2026-01-08T23:16:02.639Z
Learning: Applies to docs/conventions/**/*.{ts,tsx} : Make illegal states unrepresentable. Use discriminated unions, not optional fields. If a state combination shouldn't exist, make the type system forbid it.
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.test.{ts,tsx} : Implement integration tests for end-to-end extraction from TypeScript code to JSON output
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.test.{ts,tsx} : Implement unit tests for each predicate type in isolation with positive and negative cases
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.{ts,tsx} : Implement extraction logic as pure functions with no side effects
Learnt from: NTCoding
Repo: NTCoding/living-architecture PR: 66
File: packages/riviere-extract-conventions/src/eslint/require-component-decorator.spec.ts:19-21
Timestamp: 2026-01-08T06:46:05.503Z
Learning: In test files using typescript-eslint/rule-tester's RuleTester.run(), include an explicit it() block with an expect() assertion (e.g., expect(rule).toBeDefined()) to satisfy sonarjs/no-empty-test-file and sonarjs/assertions-in-tests lint rules, which don't recognize RuleTester's internal test blocks.
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.test.{ts,tsx} : Use ts-morph's in-memory file system (`useInMemoryFileSystem: true`) for fast isolated tests
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/conventions/testing.md:0-0
Timestamp: 2026-01-04T17:04:31.759Z
Learning: Applies to docs/conventions/**/*.spec.{ts,tsx,js,jsx} : Test edge cases for collections: empty collection, single element, duplicates, nested structures, circular references, large collections, sparse arrays, and mixed types
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/conventions/testing.md:0-0
Timestamp: 2026-01-04T17:04:31.759Z
Learning: Applies to docs/conventions/**/*.spec.{ts,tsx,js,jsx} : Use Arrange-Act-Assert structure for tests: set up test data, execute behavior, then verify outcomes
packages/riviere-cli/src/commands/extract/extract.ts (6)

1-20: LGTM: Imports are well-organized and comprehensive.

All required dependencies are properly imported and align with the command's functionality for YAML parsing, glob resolution, TypeScript AST analysis, and extraction.


22-32: LGTM: Well-structured type definitions.

The discriminated union pattern for ParseResult enables type-safe error handling, and using unknown for unparsed data is the correct approach before validation.


34-48: LGTM: Robust error handling with defensive programming.

The defensive guard for non-Error instances is appropriate, and the discriminated union return type enables type-safe error handling in the caller.


50-54: LGTM: Standard Commander.js command setup.

The command structure with required options and typed action handler follows Commander.js best practices.


76-87: LGTM: Proper config validation following extraction config patterns.

The two-step validation (type guard followed by detailed validation) correctly rejects invalid configs at load time before extraction, as per project conventions.

Based on learnings, this follows the pattern of rejecting invalid extraction configs at load time rather than during extraction.


101-104: Remove error handling concern for extractComponents—function is designed as pure with defensive returns.

The extractComponents call doesn't require try-catch wrapping. It's a pure function using defensive early returns (empty arrays) rather than throwing exceptions. Config validation already happens upfront (lines 76–87) following the "fail fast" principle: invalid configs are rejected at load time, extraction errors degrade gracefully.

Likely an incorrect or invalid review comment.

Comment thread packages/riviere-cli/package.json
Comment thread packages/riviere-cli/src/cli.ts
Comment thread packages/riviere-cli/src/commands/extract/extract.spec.ts
Comment thread packages/riviere-cli/src/commands/extract/extract.ts
Comment thread packages/riviere-cli/src/commands/extract/extract.ts
Comment thread packages/riviere-cli/src/commands/extract/extract.ts
Comment thread packages/riviere-cli/src/commands/extract/extract.ts Outdated
…e loading

Addresses CodeRabbit feedback:
- Fail fast with clear error when no files match extraction patterns
- Use addSourceFilesAtPaths for batch file loading instead of loop

Co-Authored-By: Claude Opus 4.5 <[email protected]>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @packages/riviere-cli/src/commands/extract/extract.spec.ts:
- Around line 30-35: The type guard isExtractionOutput should also validate each
element of the data array conforms to the DraftComponent shape: update
isExtractionOutput to, after confirming value.data is an array, check
value.data.every(...) and inside ensure required DraftComponent properties
(e.g., id/name/type or whatever unique fields DraftComponent defines) exist and
have correct primitive types; keep the overall signature (value is
ExtractionOutput) and reference DraftComponent and ExtractionOutput so failures
surface earlier and more clearly in tests.

In @packages/riviere-cli/src/commands/extract/extract.ts:
- Around line 54-62: The CLI currently prints error JSON but still exits with
code 0; inside the .action handler for the extract command (the function taking
ExtractOptions) set process.exitCode = 1 immediately before each early return on
error — e.g., after the existsSync config-file check and similarly in the other
error branches referenced (the ones around the checks at lines 73, 86, and 106)
so every error path sets process.exitCode = 1 before returning; update those
branches where formatError/CliErrorCode JSON is logged to set process.exitCode =
1.
- Around line 109-114: Wrap the component extraction flow in a try-catch so
runtime exceptions from Project.addSourceFilesAtPaths or extractComponents
produce structured JSON error output instead of crashing; specifically, around
the block creating new Project(), calling
project.addSourceFilesAtPaths(sourceFilePaths), and calling
extractComponents(project, sourceFilePaths, config), catch any error and return
JSON via formatError (or formatSuccess counterpart) with an appropriate error
code (add ExtractionError to error-codes.ts or reuse ValidationError) and
include the caught error.message and stack for CI debugging; ensure the catch
uses process.exitCode or returns after printing the JSON so the CLI doesn’t
throw.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cee47ce and 7aee18b.

📒 Files selected for processing (2)
  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/src/commands/extract/extract.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,js,jsx}: When writing, editing, refactoring, or reviewing code, always follow docs/conventions/software-design.md
Look for standard implementation patterns defined in docs/conventions/standard-patterns.md
Avoid anti-patterns defined in @docs/conventions/anti-patterns.md
100% test coverage is mandatory and enforced
Use domain terminology from docs/architecture/domain-terminology/contextive/definitions.glossary.yml. Do not invent new terms or use technical jargon when domain terminology exists
Never commit secrets, API keys, or credentials. Use environment variables for sensitive configuration. Do not log sensitive data (passwords, tokens, PII). Validate and sanitize all external input

Files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/src/commands/extract/extract.ts
**/*.spec.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Follow docs/conventions/testing.md for all test files

Files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
**/*.{ts,tsx,js,jsx,json,css,scss}

📄 CodeRabbit inference engine (CLAUDE.md)

All UI and UX design must conform to global brand guidelines: /docs/brand/ (logo, colors, typography, icons)

Files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/src/commands/extract/extract.ts
packages/**

📄 CodeRabbit inference engine (CLAUDE.md)

Create new shared libraries as publishable packages in the packages/ directory using pnpm nx g @nx/js:library packages/[pkg-name] --publishable --importPath=@living-architecture/[pkg-name]

Files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/src/commands/extract/extract.ts
🧠 Learnings (25)
📓 Common learnings
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/architecture/overview.md:0-0
Timestamp: 2026-01-08T22:20:13.250Z
Learning: Applies to docs/architecture/**/*extract*.ts : Use `living-architecture/riviere-extract-ts` TypeScript extractor with ts-morph for AST parsing when implementing TypeScript extraction for architecture schema components
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/architecture/overview.md:0-0
Timestamp: 2026-01-08T22:20:13.250Z
Learning: Applies to docs/architecture/**/*extract*.{json,ts} : Define extraction configuration using the JSON Schema from `living-architecture/riviere-extract-config` DSL
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-conventions/CLAUDE.md:0-0
Timestamp: 2026-01-08T07:05:01.766Z
Learning: Import and use the default extraction config from `living-architecture/riviere-extract-conventions/default-config` in extraction tooling to detect all 6 component types
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.test.{ts,tsx} : Implement integration tests for end-to-end extraction from TypeScript code to JSON output
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.{ts,tsx} : Implement extraction logic as pure functions with no side effects
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/architecture/overview.md:0-0
Timestamp: 2026-01-08T22:20:13.250Z
Learning: Applies to docs/architecture/**/*extract*.ts : Use the Rivière Builder Node.js library to programmatically construct the schema graph when implementing custom extraction code
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-config/CLAUDE.md:0-0
Timestamp: 2026-01-06T23:01:34.751Z
Learning: Applies to packages/riviere-extract-config/**/*.ts : Extraction config schema is the source of truth for valid structures. TypeScript types must mirror the schema definition to maintain consistency
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.{ts,tsx} : Reject invalid extraction configs at load time, not during extraction phase
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.{ts,tsx} : Use glob pattern matching for module-based organization of extraction rules
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/architecture/overview.md:0-0
Timestamp: 2026-01-08T22:20:13.250Z
Learning: Applies to docs/architecture/**/*.{ts,tsx} : Apply decorators from `living-architecture/riviere-extract-conventions` to mark all classes as architectural components
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: All extraction rules should come from validated ExtractionConfig provided by riviere-extract-config
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-cli/CLAUDE.md:0-0
Timestamp: 2026-01-02T11:58:27.018Z
Learning: When modifying CLI commands in the riviere-cli tool, update the corresponding workflow prompts in docs/workflow/ directory (step-1 through step-6) to keep the extraction workflow in sync
📚 Learning: 2026-01-08T17:19:17.148Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.test.{ts,tsx} : Implement integration tests for end-to-end extraction from TypeScript code to JSON output

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/src/commands/extract/extract.ts
📚 Learning: 2026-01-08T17:19:17.148Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.test.{ts,tsx} : Implement unit tests for each predicate type in isolation with positive and negative cases

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
📚 Learning: 2026-01-06T23:01:34.751Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-config/CLAUDE.md:0-0
Timestamp: 2026-01-06T23:01:34.751Z
Learning: Applies to packages/riviere-extract-config/**/*.ts : Extraction config schema is the source of truth for valid structures. TypeScript types must mirror the schema definition to maintain consistency

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/src/commands/extract/extract.ts
📚 Learning: 2026-01-08T22:20:13.250Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/architecture/overview.md:0-0
Timestamp: 2026-01-08T22:20:13.250Z
Learning: Applies to docs/architecture/**/*extract*.{json,ts} : Define extraction configuration using the JSON Schema from `living-architecture/riviere-extract-config` DSL

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/src/commands/extract/extract.ts
📚 Learning: 2026-01-08T17:19:17.148Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.{ts,tsx} : Implement extraction logic as pure functions with no side effects

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/src/commands/extract/extract.ts
📚 Learning: 2026-01-08T22:20:13.250Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/architecture/overview.md:0-0
Timestamp: 2026-01-08T22:20:13.250Z
Learning: Applies to docs/architecture/**/*extract*.ts : Use `living-architecture/riviere-extract-ts` TypeScript extractor with ts-morph for AST parsing when implementing TypeScript extraction for architecture schema components

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/src/commands/extract/extract.ts
📚 Learning: 2026-01-08T17:19:17.148Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.{ts,tsx} : Reject invalid extraction configs at load time, not during extraction phase

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/src/commands/extract/extract.ts
📚 Learning: 2026-01-08T17:19:17.148Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.test.{ts,tsx} : Use ts-morph's in-memory file system (`useInMemoryFileSystem: true`) for fast isolated tests

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/src/commands/extract/extract.ts
📚 Learning: 2026-01-08T17:19:17.148Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/vitest.config.mts : Enforce 100% code coverage using Vitest with v8 coverage and thresholds configured in vitest.config.mts

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
📚 Learning: 2026-01-08T17:19:17.148Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.{ts,tsx} : Use glob pattern matching for module-based organization of extraction rules

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/src/commands/extract/extract.ts
📚 Learning: 2026-01-07T08:54:48.071Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/workflow/code-review.md:0-0
Timestamp: 2026-01-07T08:54:48.071Z
Learning: Applies to docs/workflow/**/*.{ts,tsx,js,jsx} : Review usage of `/* v8 ignore next -- preserve */` coverage skip directives. This is only acceptable for unreachable code needed to satisfy the compiler. Most cases should be solved by extracting code or writing tests to mock behavior.

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/src/commands/extract/extract.ts
📚 Learning: 2026-01-06T08:11:15.403Z
Learnt from: NTCoding
Repo: NTCoding/living-architecture PR: 53
File: packages/riviere-extract-config/vitest.config.mts:20-20
Timestamp: 2026-01-06T08:11:15.403Z
Learning: In packages/riviere-extract-config/vitest.config.mts, the explicit tuple type assertion for the reporter configuration (`as ['text', ['lcov', { projectRoot: string }]]`) is necessary because vitest's CoverageReporter type requires the exact tuple shape; neither inference nor 'as const' produces a compatible type.

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
📚 Learning: 2026-01-04T17:04:31.759Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/conventions/testing.md:0-0
Timestamp: 2026-01-04T17:04:31.759Z
Learning: Applies to docs/conventions/**/*.spec.{ts,tsx,js,jsx} : Assert specific values, not types. Use `expect(result).toEqual(['First.', ' Second.'])` instead of `expect(result).toBeDefined()`. Specific assertions catch specific bugs

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
📚 Learning: 2026-01-04T17:04:31.759Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/conventions/testing.md:0-0
Timestamp: 2026-01-04T17:04:31.759Z
Learning: Applies to docs/conventions/**/*.spec.{ts,tsx,js,jsx} : Test domain-specific edge cases: email formats, URLs with protocols/ports, international phone formats, addresses with Unicode, currency rounding, and percentage boundaries

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
📚 Learning: 2026-01-08T22:20:13.250Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/architecture/overview.md:0-0
Timestamp: 2026-01-08T22:20:13.250Z
Learning: Applies to docs/architecture/**/*extract*.ts : Use the Rivière Builder Node.js library to programmatically construct the schema graph when implementing custom extraction code

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/src/commands/extract/extract.ts
📚 Learning: 2026-01-08T07:05:01.766Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-conventions/CLAUDE.md:0-0
Timestamp: 2026-01-08T07:05:01.766Z
Learning: Import and use the default extraction config from `living-architecture/riviere-extract-conventions/default-config` in extraction tooling to detect all 6 component types

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
  • packages/riviere-cli/src/commands/extract/extract.ts
📚 Learning: 2026-01-08T06:46:00.609Z
Learnt from: NTCoding
Repo: NTCoding/living-architecture PR: 66
File: packages/riviere-extract-conventions/src/eslint/require-component-decorator.spec.ts:19-21
Timestamp: 2026-01-08T06:46:00.609Z
Learning: In test files using typescript-eslint/rule-tester's RuleTester.run(), ensure there is an explicit it() block with at least one expect() assertion (e.g., expect(rule).toBeDefined()) to satisfy sonarjs/no-empty-test-file and sonarjs/assertions-in-tests lint rules, which don’t recognize RuleTester's internal test blocks. Apply this pattern to all spec.ts test files to maintain consistency and pass lint checks.

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.spec.ts
📚 Learning: 2026-01-08T22:20:13.250Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/architecture/overview.md:0-0
Timestamp: 2026-01-08T22:20:13.250Z
Learning: Applies to docs/architecture/**/*.{ts,tsx} : Apply decorators from `living-architecture/riviere-extract-conventions` to mark all classes as architectural components

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.ts
📚 Learning: 2026-01-06T23:01:34.751Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-config/CLAUDE.md:0-0
Timestamp: 2026-01-06T23:01:34.751Z
Learning: All validation of extraction config must occur at config load time, not during extraction. Invalid configs should fail fast with clear error messages that include paths and descriptive information

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.ts
📚 Learning: 2026-01-08T23:16:02.639Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/conventions/software-design.md:0-0
Timestamp: 2026-01-08T23:16:02.639Z
Learning: Applies to docs/conventions/**/*.{ts,tsx,js,jsx} : Fail-Fast Error Handling: Validate and throw clear errors instead of using fallback chains. Error format: `Expected [X]. Got [Y]. Context: [debugging info]`

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.ts
📚 Learning: 2026-01-08T23:16:02.639Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/conventions/software-design.md:0-0
Timestamp: 2026-01-08T23:16:02.639Z
Learning: Applies to docs/conventions/**/*.{ts,tsx,js,jsx} : Fail-fast over silent fallbacks. Never use fallback chains (`value ?? backup ?? 'unknown'`). If data should exist, validate and throw a clear error.

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.ts
📚 Learning: 2026-01-07T08:54:48.071Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: docs/workflow/code-review.md:0-0
Timestamp: 2026-01-07T08:54:48.071Z
Learning: Applies to docs/workflow/**/*.{ts,tsx,js,jsx} : Avoid dangerous fallback values that hide bugs. Do not use `??` or `||` operators without clear reason for providing defaults. If a value is required, make it required rather than guessing at defaults. Exceptions: optional parameters with documented defaults, configuration with explicit optional semantics, and test data with placeholder values.

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.ts
📚 Learning: 2026-01-08T17:19:17.148Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: Applies to packages/riviere-extract-ts/**/*.{ts,tsx} : Use ts-morph for TypeScript AST parsing instead of other parsers

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.ts
📚 Learning: 2026-01-08T17:19:17.148Z
Learnt from: CR
Repo: NTCoding/living-architecture PR: 0
File: packages/riviere-extract-ts/CLAUDE.md:0-0
Timestamp: 2026-01-08T17:19:17.148Z
Learning: All extraction rules should come from validated ExtractionConfig provided by riviere-extract-config

Applied to files:

  • packages/riviere-cli/src/commands/extract/extract.ts
🧬 Code graph analysis (1)
packages/riviere-cli/src/commands/extract/extract.spec.ts (2)
packages/riviere-cli/src/cli.ts (1)
  • createProgram (44-78)
packages/riviere-cli/src/command-test-fixtures.ts (4)
  • TestContext (55-59)
  • createTestContext (61-67)
  • setupCommandTest (69-83)
  • parseErrorOutput (27-37)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: browser-tests (firefox)
  • GitHub Check: Analyze
  • GitHub Check: browser-tests (webkit)
  • GitHub Check: browser-tests (chromium)
  • GitHub Check: main
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (5)
packages/riviere-cli/src/commands/extract/extract.ts (2)

34-48: LGTM!

The parseConfigFile function correctly implements fail-fast error handling with a discriminated union return type. The v8 ignore directive is appropriately documented as a defensive guard for an edge case.


92-107: LGTM!

The glob resolution correctly handles patterns relative to the config directory, and the empty-match error provides actionable debugging context (patterns and config directory).

packages/riviere-cli/src/commands/extract/extract.spec.ts (3)

51-55: LGTM!

The command registration test correctly verifies the extract command is registered at the top level. The optional chaining handles the edge case gracefully.


58-125: LGTM!

Comprehensive error scenario coverage with specific assertions. Tests verify all acceptance criteria: missing config, invalid YAML, invalid schema, and no-matches cases. Each assertion checks specific values rather than just types, per testing conventions.


131-176: LGTM!

Solid end-to-end integration test that exercises the full extraction flow from source file through JSON output. The test uses real file operations and validates the complete output structure.

Consider adding a test case for extraction failures (e.g., unreadable source file, malformed TypeScript) once the try-catch handling is added to the command implementation. This would ensure CI-facing error output remains structured even when extraction throws.

Comment thread packages/riviere-cli/src/commands/extract/extract.spec.ts
Comment thread packages/riviere-cli/src/commands/extract/extract.ts
Comment thread packages/riviere-cli/src/commands/extract/extract.ts
- Add process.exit(1) for all error paths to ensure non-zero exit codes in CI
- Add engines field requiring Node.js 20+
- Update generate-docs.ts to include extract command in CLI documentation
- Add ProcessExitError to test fixtures to properly test process.exit behavior
- Update all extract command error tests to catch and verify ProcessExitError

Addresses critical and major feedback from CodeRabbit review.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
NTCoding and others added 3 commits January 9, 2026 21:52
- Enable vitest plugin rules: prefer-strict-equal, consistent-test-filename,
  require-to-throw-message, no-conditional-expect, no-conditional-in-test,
  prefer-called-with, prefer-to-have-length, max-expects (9), prefer-spy-on

- Rename all .test.ts files to .spec.ts in eclair app (consistent-test-filename)

- Replace toEqual with toStrictEqual across all test files (prefer-strict-equal)

- Add error message patterns to toThrow() assertions (require-to-throw-message)

- Create assertDefined<T>() and assertHTMLInputElement() helpers to replace
  conditional logic in tests (no-conditional-in-test, no-conditional-expect)

- Add argument matchers (expect.anything(), expect.any()) for toHaveBeenCalledWith()

- Use toMatchObject() for class instance comparisons where toStrictEqual fails

- Disable no-unsafe-assignment in test files to allow expect.any() matchers

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@sonarqubecloud

sonarqubecloud Bot commented Jan 9, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[M4-D4.1] Add riviere extract command to CLI

1 participant