Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -110,15 +110,15 @@ jobs:

- name: Install portable pipeline
shell: pwsh
run: .\install-code-intel-pipeline.ps1 -RepoPath . -RepairSkillLinks -Json
run: .\install-code-intel-pipeline.ps1 -RepoPath . -RepairSkillLinks -RequireRepowise:$false -Json

- name: Add pipeline tools PATH
shell: pwsh
run: Add-Content -Path $env:GITHUB_PATH -Value "$env:LOCALAPPDATA\code-intel\bin"

- name: Doctor
shell: pwsh
run: .\check-code-intel-tools.ps1 -RepoPath .
run: .\check-code-intel-tools.ps1 -RepoPath . -RequireRepowise:$false

- name: GitHub research contract tests
shell: pwsh
Expand Down Expand Up @@ -273,12 +273,12 @@ jobs:
- name: Install portable pipeline
shell: pwsh
run: |
$result = ./install-code-intel-pipeline.ps1 -RepoPath . -RepairSkillLinks -Json | ConvertFrom-Json
$result = ./install-code-intel-pipeline.ps1 -RepoPath . -RepairSkillLinks -RequireRepowise:$false -Json | ConvertFrom-Json
Add-Content -Path $env:GITHUB_PATH -Value $result.paths.bin

- name: Doctor
shell: pwsh
run: ./check-code-intel-tools.ps1 -RepoPath . -Json
run: ./check-code-intel-tools.ps1 -RepoPath . -RequireRepowise:$false -Json

- name: Pipeline smoke
shell: pwsh
Expand Down
19 changes: 18 additions & 1 deletion Install-SentruxVlangOverlay.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -127,21 +127,38 @@ if (-not $NoReadOnlyLock) {
}
}

$validationStatus = "skipped"
$validationDetail = ""

if (-not $SkipValidate) {
if (-not (Get-Command sentrux -ErrorAction SilentlyContinue)) {
throw "sentrux CLI not found in PATH"
}
& sentrux plugin validate $targetRoot
$validateOutput = & sentrux plugin validate $targetRoot 2>&1
$validationDetail = ($validateOutput | ForEach-Object { $_.ToString() } | Out-String).Trim()
if ($LASTEXITCODE -ne 0) {
if ($validationDetail -match "unknown command 'plugin'" -or $validationDetail -match "unknown command `"plugin`"") {
$validationStatus = "skipped"
$validationDetail = "current sentrux is lite/shim and has no plugin command"
}
else {
throw "sentrux plugin validate failed for $targetRoot"
}
}
else {
$validationStatus = "passed"
}
}

$global:LASTEXITCODE = 0

[pscustomobject][ordered]@{
status = "installed"
plugin = "vlang"
platform = $effectivePlatform
target = $targetRoot
backup = if (Test-Path -LiteralPath $backupPath) { $backupPath } else { $null }
readOnlyLock = -not $NoReadOnlyLock
validation = $validationStatus
validationDetail = $validationDetail
} | ConvertTo-Json -Depth 4
187 changes: 187 additions & 0 deletions Invoke-CodeIntelOrchestrator.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
param(
[ValidateSet("Validate", "List", "Plan")]
[string]$Action = "Validate",

[string]$Capability = "",
[string]$RepoPath = "",

[ValidateSet("lite", "normal", "full")]
[string]$Mode = "normal",

[string]$Manifest = "",
[switch]$Json
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

$root = Split-Path -Parent $PSCommandPath
if ([string]::IsNullOrWhiteSpace($Manifest)) {
$Manifest = Join-Path $root "orchestration\integrations.json"
}
Comment on lines +18 to +21

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Root resolution diverges from the Rust orchestrator for custom -Manifest paths.

$root is always the script's own directory (Line 18), and is reused for resolving entrypoint paths even when -Manifest points elsewhere (Line 105). The Rust engine (orchestration.rs::root_for_manifest) instead derives the root from the manifest's own location (parent, or grandparent when the parent directory is named orchestration). With a custom -Manifest, this script will validate entrypoints against the wrong root, producing results that disagree with code-intel.exe orchestrate for the same manifest.

🔧 Proposed fix to mirror Rust's root_for_manifest
 $root = Split-Path -Parent $PSCommandPath
 if ([string]::IsNullOrWhiteSpace($Manifest)) {
     $Manifest = Join-Path $root "orchestration\integrations.json"
+} else {
+    $manifestParent = Split-Path -Parent $Manifest
+    if ((Split-Path -Leaf $manifestParent) -eq "orchestration") {
+        $root = Split-Path -Parent $manifestParent
+    } else {
+        $root = $manifestParent
+    }
 }

Also applies to: 104-109

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Invoke-CodeIntelOrchestrator.ps1` around lines 18 - 21, The root resolution
in Invoke-CodeIntelOrchestrator.ps1 currently always uses the script directory,
which causes custom -Manifest paths to validate against the wrong base. Update
the root calculation near the initial $root assignment and where entrypoint
paths are resolved so it mirrors orchestration.rs::root_for_manifest: derive the
root from the manifest’s directory, or its grandparent when the parent folder is
named orchestration. Make sure the same root is used consistently for manifest
loading and entrypoint validation when -Manifest is provided.


function Get-JsonProperty {
param(
[object]$Object,
[string]$Name
)

if ($null -eq $Object) { return $null }
$prop = $Object.PSObject.Properties[$Name]
if ($null -eq $prop) { return $null }
return $prop.Value
}
Comment on lines +23 to +33

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

In PowerShell, accessing properties dynamically using $Object.$Name is more idiomatic, robust, and compatible with both PSCustomObject and Hashtable than manually traversing PSObject.Properties.

function Get-JsonProperty {
    param(
        [object]$Object,
        [string]$Name
    )

    if ($null -eq $Object) { return $null }
    return $Object.$Name
}


function ConvertTo-Array {
param([object]$Value)

if ($null -eq $Value) { return @() }
if ($Value -is [System.Array]) { return @($Value) }
return @($Value)
}

function Expand-CommandTemplate {
param(
[string]$Template,
[string]$RepoPath,
[string]$Mode
)

$expanded = $Template.Replace("<mode>", $Mode)
if (-not [string]::IsNullOrWhiteSpace($RepoPath)) {
$expanded = $expanded.Replace("<repo-path>", $RepoPath)
}
return $expanded
}

if (-not (Test-Path -LiteralPath $Manifest -PathType Leaf)) {
throw "Orchestration manifest missing: $Manifest"
}

$manifestData = Get-Content -LiteralPath $Manifest -Raw | ConvertFrom-Json
$stages = ConvertTo-Array (Get-JsonProperty $manifestData "stages")
$integrations = ConvertTo-Array (Get-JsonProperty $manifestData "integrations")

$errors = New-Object System.Collections.Generic.List[string]
$stageIds = @{}
foreach ($stage in $stages) {
$id = [string](Get-JsonProperty $stage "id")
if ([string]::IsNullOrWhiteSpace($id)) {
$errors.Add("stage id is empty")
continue
}
if ($stageIds.ContainsKey($id)) {
$errors.Add("duplicate stage id: $id")
}
else {
$stageIds[$id] = $stage
}
}

$integrationIds = @{}
foreach ($integration in $integrations) {
$id = [string](Get-JsonProperty $integration "id")
$stage = [string](Get-JsonProperty $integration "stage")
$entrypoint = [string](Get-JsonProperty $integration "entrypoint")
$capabilities = ConvertTo-Array (Get-JsonProperty $integration "capabilities")

if ([string]::IsNullOrWhiteSpace($id)) {
$errors.Add("integration id is empty")
continue
}
if ($integrationIds.ContainsKey($id)) {
$errors.Add("duplicate integration id: $id")
}
else {
$integrationIds[$id] = $integration
}
if (-not $stageIds.ContainsKey($stage)) {
$errors.Add("integration $id references unknown stage: $stage")
}
if ([string]::IsNullOrWhiteSpace($entrypoint)) {
$errors.Add("integration $id has no entrypoint")
}
elseif ($entrypoint -like "*.ps1" -or $entrypoint -like "*.py" -or $entrypoint -like "*.toml" -or $entrypoint -like "*.rs") {
$candidate = Join-Path $root $entrypoint
if (-not (Test-Path -LiteralPath $candidate -PathType Leaf)) {
$errors.Add("integration $id entrypoint missing: $entrypoint")
}
}
if ($capabilities.Count -eq 0) {
$errors.Add("integration $id exposes no capabilities")
}
}

$stageOrder = @{}
foreach ($stage in $stages) {
$stageOrder[[string](Get-JsonProperty $stage "id")] = [int](Get-JsonProperty $stage "order")
}

$selected = @($integrations | Where-Object {
if ([string]::IsNullOrWhiteSpace($Capability)) { return $true }
$caps = ConvertTo-Array (Get-JsonProperty $_ "capabilities")
return ($caps -contains $Capability) -or ([string](Get-JsonProperty $_ "id") -eq $Capability) -or ([string](Get-JsonProperty $_ "stage") -eq $Capability)
} | Sort-Object @{ Expression = { $stageOrder[[string](Get-JsonProperty $_ "stage")] } }, @{ Expression = { [string](Get-JsonProperty $_ "id") } })

$plan = @($selected | ForEach-Object {
$commands = Get-JsonProperty $_ "commands"
$expandedCommands = [ordered]@{}
if ($null -ne $commands) {
foreach ($command in $commands.PSObject.Properties) {
$expandedCommands[$command.Name] = Expand-CommandTemplate ([string]$command.Value) $RepoPath $Mode
}
}

[pscustomobject][ordered]@{
id = [string](Get-JsonProperty $_ "id")
stage = [string](Get-JsonProperty $_ "stage")
kind = [string](Get-JsonProperty $_ "kind")
required = [bool](Get-JsonProperty $_ "required")
entrypoint = [string](Get-JsonProperty $_ "entrypoint")
capabilities = @(ConvertTo-Array (Get-JsonProperty $_ "capabilities"))
commands = $expandedCommands
artifactContract = @(ConvertTo-Array (Get-JsonProperty $_ "artifactContract"))
extensionPoint = [string](Get-JsonProperty $_ "extensionPoint")
}
})

$result = [pscustomobject][ordered]@{
ok = $errors.Count -eq 0
action = $Action
manifest = $Manifest
policy = Get-JsonProperty $manifestData "policy"
errors = @($errors)
stages = @($stages | Sort-Object @{ Expression = { [int](Get-JsonProperty $_ "order") } })
integrations = if ($Action -eq "Validate") { @() } else { $plan }
plan = if ($Action -eq "Plan") { $plan } else { @() }
}

if ($Json) {
$result | ConvertTo-Json -Depth 12
}
else {
if (-not $result.ok) {
Write-Host "Code Intel orchestration: FAILED"
foreach ($errorText in $errors) { Write-Host "- $errorText" }
}
elseif ($Action -eq "Validate") {
Write-Host "Code Intel orchestration: OK"
Write-Host "Manifest: $Manifest"
Write-Host "Stages: $($stages.Count)"
Write-Host "Integrations: $($integrations.Count)"
}
else {
Write-Host "Code Intel orchestration: $Action"
foreach ($item in $plan) {
Write-Host "$($item.stage): $($item.id) [$($item.kind)] entry=$($item.entrypoint)"
if ($Action -eq "Plan") {
foreach ($command in $item.commands.GetEnumerator()) {
Write-Host " $($command.Key): $($command.Value)"
}
}
}
}
}

if (-not $result.ok) { exit 1 }
exit 0
59 changes: 46 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ GPT 娘坐在空白处,不紧不慢。她把文件列成星图,把依赖连
- `Repowise` 记住项目语义,下一次不用从零开始。
- `CodeNexus-lite` 给 Agent 一个低成本的上下文入口。
- 治理层把这些信号收束成机器可读的下一步计划。
- 编排层规定这些能力怎么融合,避免以后每接一个新项目就到处散写外部调用。

## 适合谁

Expand Down Expand Up @@ -167,6 +168,9 @@ install -> doctor -> smoke test

| 工具 | 角色 | 产物 |
| --- | --- | --- |
| Integration orchestration | 融合注册、能力编排、扩展边界 | `target/debug/code-intel.exe orchestrate` |
| `code-intel` Rust CLI | orchestration、artifact resume、failure classify、artifact doctor | `target/debug/code-intel.exe` |
| `code-nexus-lite` Rust worker | CodeNexus scan/lite/doctor worker | `target/debug/code-nexus-lite.exe` |
| `rg` | 快速文件清单、文本搜索 | `files.txt` |
| `Repowise` | 语义索引、长期记忆、项目上下文 | `.repowise/` 或 scoped shadow |
| `Repomix` | 把本地或远程仓库打包成 AI 友好的单文件上下文 | `repomix-output.md`、`repomix-summary.json` |
Expand All @@ -177,6 +181,16 @@ install -> doctor -> smoke test

这几个工具分工不同。不要把它们混成一个 RAG 糊糊。

新增项目或新方式时,先注册到 `orchestration/integrations.json`,再接 adapter。不要直接把新的外部 CLI 调用散进主流程。

查看当前编排:

```powershell
cargo build -p code-intel
.\target\debug\code-intel.exe orchestrate --action Validate
.\target\debug\code-intel.exe orchestrate --action Plan --repo C:\path\to\your\repo --mode normal
```

## 输出在哪里

每次运行会创建一个带时间戳的目录:
Expand Down Expand Up @@ -209,6 +223,9 @@ Skill quality guidance lives in
Implementation minimalism guidance lives in
[`docs/implementation-minimalism-benchmark.md`](docs/implementation-minimalism-benchmark.md).

Integration orchestration rules live in
[`docs/integration-orchestration.md`](docs/integration-orchestration.md).

Measured minimalism impact lives in
[`docs/ponytail-impact-scoreboard.md`](docs/ponytail-impact-scoreboard.md).

Expand Down Expand Up @@ -428,7 +445,7 @@ sentrux plugin list

## Repowise 语义记忆

Repowise 是可选语义记忆层。默认单步超时 `180` 秒;超时会跳过,不拖死整轮
Repowise 是硬依赖语义记忆层。默认单步超时 `180` 秒;超时会作为 Repowise 失败写进报告,不再静默跳过

```powershell
.\run-code-intel.ps1 -RepoPath C:\path\to\repo -Mode normal -RepowiseTimeoutSeconds 60
Expand Down Expand Up @@ -456,19 +473,34 @@ Repowise 是可选语义记忆层。默认单步超时 `180` 秒;超时会跳
graph_missing: understand graph
```

在支持该技能的 Agent 中运行
先运行项目内 Rust 图谱 provider

```text
/understand C:\path\to\repo --language zh
```powershell
.\target\debug\code-intel.exe graph --repo C:\path\to\repo --language zh --write --json
```

完整重建:

```text
/understand C:\path\to\repo --language zh --full
```powershell
.\target\debug\code-intel.exe graph --repo C:\path\to\repo --language zh --full --write --json
```

然后重新运行 pipeline。
然后重新运行 pipeline。`/understand C:\path\to\repo --language zh` 只作为兼容兜底,或在你明确需要外部 Understand Anything 更富图谱时使用。

## 全局 Provider Route

Repowise 和 Understand-compatible graph 统一走 `code-intel provider` 规范,再由 `code-intel route` 暴露入口:

```powershell
.\target\debug\code-intel.exe provider --action Validate --json
.\target\debug\code-intel.exe provider --action Plan --provider repowise --operation index --repo C:\path\to\repo --json
.\target\debug\code-intel.exe provider --action Plan --provider understand --operation graph --repo C:\path\to\repo --json
.\target\debug\code-intel.exe route --action List --json
.\target\debug\code-intel.exe route --action Plan --provider repowise --operation index --repo C:\path\to\repo --json
.\target\debug\code-intel.exe route --action Plan --provider understand --operation graph --repo C:\path\to\repo --json
```

HTTP route 使用命名空间:`/api/providers/repowise/*`、`/api/providers/understand/*`。旧的 `/scan`、`/lite`、`/doctor`、`/understand` 只能作为兼容入口。

## 规则文件

Expand Down Expand Up @@ -602,8 +634,8 @@ CI 使用 Sentrux lite core 保底,所以 runner 没装真实 `sentrux` 时也

运行:

```text
/understand C:\path\to\repo --language zh
```powershell
.\target\debug\code-intel.exe graph --repo C:\path\to\repo --language zh --write --json
```

再重跑 pipeline。
Expand Down Expand Up @@ -656,13 +688,14 @@ MIT

```powershell
cargo build -p code-intel
.\target\debug\code-intel.exe orchestrate --action Validate --json
.\target\debug\code-intel.exe orchestrate --action Plan --repo C:\path\to\your\repo --mode normal --json
.\target\debug\code-intel.exe resume --repo C:\path\to\your\repo
.\target\debug\code-intel.exe resume --repo C:\path\to\your\repo --artifact-root C:\path\to\artifacts
.\target\debug\code-intel.exe resume --repo C:\path\to\your\repo --json
.\target\debug\code-intel.exe classify --report C:\path\to\artifact\report.json
```

The Rust CLI is currently a cross-session artifact reader. It does not replace
the PowerShell scanner yet; it locates the latest artifact run, reads
`report.json` and `hospital-report.json`, then prints the next protocol and the
next file an Agent should read.
The Rust CLI owns integration orchestration and cross-session artifact reads.
PowerShell scripts remain Windows compatibility wrappers for scanner steps that
have not yet been absorbed into Rust.
Loading
Loading