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
12 changes: 11 additions & 1 deletion .bumpversion.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# SPDX-License-Identifier: Apache-2.0

[tool.bumpversion]
current_version = "0.26.0"
current_version = "0.26.1"
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
serialize = ["{major}.{minor}.{patch}"]
commit = true
Expand Down Expand Up @@ -63,3 +63,13 @@ replace = "minimum required Core version (`v{new_version}`)"
filename = "README.md"
search = "virtual environment containing Core `v{current_version}` or higher"
replace = "virtual environment containing Core `v{new_version}` or higher"

[[tool.bumpversion.files]]
filename = "CONTRIBUTING.md"
search = "**Zenzic Core `v{current_version}`** (`MIN_CORE_VERSION = '{current_version}'` in `src/extension.ts`)."
replace = "**Zenzic Core `v{new_version}`** (`MIN_CORE_VERSION = '{new_version}'` in `src/extension.ts`)."

[[tool.bumpversion.files]]
filename = "CONTRIBUTING.md"
search = "| **Zenzic Core** | ≥ {current_version} |"
replace = "| **Zenzic Core** | ≥ {new_version} |"
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.26.1] - 2026-07-27

### Changed

- **Core Parity Alignment (`VSCODE-ALIGN-007`)**: Realigned the VS Code extension release notes with Zenzic Core `0.26.1`, including adapter contract formalization (`CORE-FIX-005`) and VSM URL route parity improvements (`CORE-FIX-003`).

### Fixed
- **Tilde Expansion (`VSCODE-FIX-006`)**: Implemented native tilde (`~`) and `${workspaceFolder}` expansion for the `zenzic.executablePath` setting, eradicating `ENOENT` errors when configuring custom binary paths in Unix-like environments.
- **Documentation (`DOCS-VSCODE-001`)**: Added factual documentation explaining the architectural split between real-time incremental diagnostics (PROBLEMS panel) and the on-demand global DQS computation (Status Bar).

## [0.26.0] - 2026-07-26

### Added
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Zenzic is structured across three independent, dedicated repositories:

- **Thin Client Sovereignty**: `zenzic-vscode` contains **zero** AST parsing, regex checks, or link validation rules. All analysis logic resides in Zenzic Core (`zenzic lsp`).
- **Protocol Parity**: The extension communicates via standard Language Server Protocol (LSP) over stdio.
- **Minimum Core Baseline**: Currently pinned to **Zenzic Core `v0.25.0`** (`MIN_CORE_VERSION = '0.25.0'` in `src/extension.ts`).
- **Minimum Core Baseline**: Currently pinned to **Zenzic Core `v0.26.1`** (`MIN_CORE_VERSION = '0.26.1'` in `src/extension.ts`).

---

Expand All @@ -51,7 +51,7 @@ To maintain security, architectural integrity, and legal compliance, all contrib
| **npm** | required | Package manager |
| **just** | required | Task runner — `cargo install just` or via OS package manager |
| **reuse** | required | SPDX license auditor (`uv tool install reuse`) |
| **Zenzic Core** | ≥ 0.25.0 | Core engine (`uv tool install zenzic`) |
| **Zenzic Core** | ≥ 0.26.1 | Core engine (`uv tool install zenzic`) |

---

Expand Down
48 changes: 40 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,18 @@ Hover over any diagnostic to view the exact Z-Code, DQS score penalty, and remed
### 5. DQS Workspace UI
Stream Document Quality Score (DQS) updates directly to the status bar, providing real-time visibility into overall repository health.

### Real-Time Diagnostics vs. Global DQS

To guarantee sub-50ms performance, Zenzic operates with a strict separation of concerns in the editor:

- **Real-Time Diagnostics (PROBLEMS Panel):** AST rules (e.g., Z502, Z505) and local topology checks are executed incrementally in memory on every keystroke.
- **Global DQS (Status Bar):** The Documentation Quality Score requires a full repository audit. To prevent editor lag, the DQS is computed *on-demand*. Click the `Zenzic DQS` item in the Status Bar to execute a background CLI bridge and update the global score.

---

## Requirements

This extension requires **Zenzic Core v0.26.0 or higher**.
This extension requires **Zenzic Core v0.26.1 or higher**.

We recommend installing or updating the global binary via `uv`:

Expand All @@ -59,38 +66,63 @@ pip install --upgrade zenzic

By default, the extension resolves the `zenzic` executable from your system `$PATH`.

If you use a local virtual environment or custom installation path, configure the executable path in your workspace or user `settings.json`:
The extension currently contributes one user-facing setting:

- `zenzic.executablePath`: path to the `zenzic` executable or to the virtual-environment binary you want the extension to use. The extension expands `${workspaceFolder}` and a leading `~/` or `~\` automatically.

If you use a local virtual environment or custom installation path, configure it in your workspace or user `settings.json`:

```json
{
"zenzic.executablePath": "${workspaceFolder}/.venv/bin/zenzic"
}
```

User-scoped home-directory paths are also supported:

```json
{
"zenzic.executablePath": "${workspaceFolder}/.venv/bin/zenzic",
"zenzic.trace.server": "verbose"
"zenzic.executablePath": "~/custom_path/.venv/bin/zenzic"
}
```

## Commands

The extension contributes the following commands to the Command Palette:

- `Zenzic: Start Server`
- `Zenzic: Stop Server`
- `Zenzic: Restart Server`
- `Zenzic: Compute Global DQS`

---

## Troubleshooting

### Zenzic: Outdated Core

- **Cause**: The executable resolved by the extension is older than the minimum required Core version (`v0.26.0`).
- **Cause**: The executable resolved by the extension is older than the minimum required Core version (`v0.26.1`).
- **Remediation**: Upgrade your global binary:
```bash
uv tool install --force zenzic
```
Or point `zenzic.executablePath` in `settings.json` to a virtual environment containing Core `v0.26.0` or higher.
Or point `zenzic.executablePath` in `settings.json` to a virtual environment containing Core `v0.26.1` or higher.


### Zenzic: Not Found (ENOENT)

- **Cause**: The `zenzic` executable is not present in the system `$PATH`. This commonly occurs in Flatpak, Snap, or isolated terminal environments where user binary directories (`~/.local/bin`) are omitted from process environments.
- **Remediation**: Specify the absolute path to the binary in `settings.json`:
- **Remediation**: Specify an explicit path to the binary in `settings.json`. `${workspaceFolder}` and leading `~/` / `~\` are expanded automatically:
```json
{
"zenzic.executablePath": "/home/user/.local/bin/zenzic"
"zenzic.executablePath": "~/custom_path/.venv/bin/zenzic"
}
```
- **Null-workspace note**: `${workspaceFolder}` requires an open workspace folder. If you open a standalone file without a workspace, use an absolute path or a `~/...` path instead.

### Logs and Observability

The extension creates the `Zenzic Language Server` output channel. Use it to inspect startup failures, transport errors, and language-server logs when diagnostics do not appear as expected.

---

Expand Down
10 changes: 5 additions & 5 deletions RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

| Field | Value |
| :--- | :--- |
| **Extension Version** | 0.26.0 |
| **Pinned Core** | `zenzic>=0.26.0` |
| **Extension Version** | 0.26.1 |
| **Pinned Core** | `zenzic>=0.26.1` |
| **Date** | 2026-07-11 |

## 1. Pre-Flight Checklist
Expand All @@ -25,7 +25,7 @@ Before bumping the version, ensure the workspace is pristine:
Do not manually edit version strings. Rely on the automated pipeline.

```bash
# Automate version bump (updates package.json, CHANGELOG, and this file)
# Automate version bump (updates package.json, README.md, CHANGELOG, RELEASE.md, and CONTRIBUTING.md)
just release <patch|minor|major>
```

Expand All @@ -43,8 +43,8 @@ git checkout main
git pull origin main

# 3. Create the immutable signed tag pointing to the HEAD of origin/main
git tag -s -m "Release v0.26.0" v0.26.0
git push origin v0.26.0
git tag -s -m "Release v0.26.1" v0.26.1
git push origin v0.26.1
```

## 4. Distribute (Automated)
Expand Down
23 changes: 18 additions & 5 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ set shell := ["bash", "-c"]
# just verify — lint + tsc (pre-push gate)
# just release <part> — bump version (patch|minor|major)
# just release-dry <p> — dry-run bump, no file writes
# just pin-core <ver> — realign Zenzic Core pin in README + RELEASE.md
# just pin-core <ver> — realign Zenzic Core pin in README + RELEASE.md + CONTRIBUTING.md
# just pin-core-dry — show what pin-core would change (no writes)
# just versions — show extension version and pinned core version
# just clean — remove generated artefacts (out/, *.vsix, .tsbuildinfo)
Expand Down Expand Up @@ -51,7 +51,7 @@ versions:
echo "core-pinned: $PINNED (RELEASE.md)"
echo "min-core-ts: $EXT_MIN (src/extension.ts)"

# Realign the Zenzic Core pin in README.md, RELEASE.md, and src/extension.ts.
# Realign the Zenzic Core pin in README.md, RELEASE.md, CONTRIBUTING.md, and src/extension.ts.
# Usage: just pin-core <version>
pin-core version:
#!/usr/bin/env bash
Expand All @@ -67,9 +67,14 @@ pin-core version:
echo "Aligning Zenzic Core pin to {{version}}..."
sed -i 's/uv tool install zenzic==[0-9.]*/uv tool install zenzic=={{version}}/g' README.md
sed -i 's/pip install zenzic==[0-9.]*/pip install zenzic=={{version}}/g' README.md
sed -i 's/Zenzic Core v[0-9.]* or higher/Zenzic Core v{{version}} or higher/g' README.md
sed -i 's/minimum required Core version (`v[0-9.]*`)/minimum required Core version (`v{{version}}`)/g' README.md
sed -i 's/virtual environment containing Core `v[0-9.]*` or higher/virtual environment containing Core `v{{version}}` or higher/g' README.md
sed -i 's/| \*\*Pinned Core\*\* | .* |/| **Pinned Core** | `zenzic>={{version}}` |/' RELEASE.md
sed -i "s/\*\*Zenzic Core \`v[0-9.]*\`\*\* (\`MIN_CORE_VERSION = '[0-9.]*'\` in \`src\\/extension.ts\`)./**Zenzic Core \`v{{version}}\`** (\`MIN_CORE_VERSION = '{{version}}'\` in \`src\\/extension.ts\`)./g" CONTRIBUTING.md
sed -i 's/| \*\*Zenzic Core\*\* | ≥ [0-9.]* |/| **Zenzic Core** | ≥ {{version}} |/' CONTRIBUTING.md
sed -i "s/const MIN_CORE_VERSION = '[0-9.]*';/const MIN_CORE_VERSION = '{{version}}';/g" src/extension.ts
git add README.md RELEASE.md src/extension.ts
git add README.md RELEASE.md CONTRIBUTING.md src/extension.ts
git commit -S -s -m "chore(deps): pin zenzic core to {{version}}"

# Simulate a Zenzic Core pin realignment and print the diff without writing files.
Expand All @@ -84,13 +89,21 @@ pin-core-dry version:
echo "==> Dry-run: changes that 'just pin-core {{version}}' would apply"
echo ""
echo "--- README.md ---"
grep -n 'zenzic==[0-9.]*' README.md \
| sed 's/zenzic==[0-9.]*/zenzic=={{version}}/' || echo " (no occurrences)"
grep -nE 'zenzic==[0-9.]*|Zenzic Core v[0-9.]+ or higher|minimum required Core version \(`v[0-9.]+`\)|virtual environment containing Core `v[0-9.]+` or higher' README.md \
| sed -E \
-e 's/zenzic==[0-9.]*/zenzic=={{version}}/g' \
-e 's/Zenzic Core v[0-9.]+ or higher/Zenzic Core v{{version}} or higher/g' \
-e 's/minimum required Core version \(`v[0-9.]+`\)/minimum required Core version (`v{{version}}`)/g' \
-e 's/virtual environment containing Core `v[0-9.]+` or higher/virtual environment containing Core `v{{version}}` or higher/g' || echo " (no occurrences)"
echo ""
echo "--- RELEASE.md ---"
grep -n 'Pinned Core' RELEASE.md \
| sed 's/zenzic>=[0-9.]*/zenzic>={{version}}/' || echo " (no occurrences)"
echo ""
echo "--- CONTRIBUTING.md ---"
grep -nE 'Minimum Core Baseline|\| \*\*Zenzic Core\*\* \|' CONTRIBUTING.md \
| sed -E "s/\*\*Zenzic Core \`v[0-9.]+\`\*\*/**Zenzic Core \`v{{version}}\`**/g; s/MIN_CORE_VERSION = '[0-9.]+'/MIN_CORE_VERSION = '{{version}}'/g; s/\| \*\*Zenzic Core\*\* \| ≥ [0-9.]+ \|/| **Zenzic Core** | ≥ {{version}} |/g" || echo " (no occurrences)"
echo ""
echo "--- src/extension.ts ---"
grep -n "MIN_CORE_VERSION = '[0-9.]*';" src/extension.ts \
| sed "s/MIN_CORE_VERSION = '[0-9.]*';/MIN_CORE_VERSION = '{{version}}';/" || echo " (no occurrences)"
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "zenzic-vscode",
"displayName": "Zenzic",
"description": "Deterministic Document Integrity Engine and SAST for Markdown/MDX graphs.",
"version": "0.26.0",
"version": "0.26.1",
"publisher": "pythonwoods",
"engines": {
"vscode": "^1.125.0"
Expand Down Expand Up @@ -57,7 +57,7 @@
"zenzic.executablePath": {
"type": "string",
"default": "zenzic",
"description": "Path to the Zenzic executable or virtual environment binary."
"description": "Path to the Zenzic executable or virtual environment binary. Supports ${workspaceFolder} and leading ~/ or ~\\."
}
}
}
Expand Down
41 changes: 34 additions & 7 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,28 @@ let dqsStatusBarItem: vscode.StatusBarItem | undefined;
// A2 fix: guard flag prevents concurrent restart calls.
let restarting = false;

const MIN_CORE_VERSION = '0.26.0';
const MIN_CORE_VERSION = '0.26.1';

/**
* Expand supported user-facing path variables in zenzic.executablePath.
* Returns undefined when ${workspaceFolder} is configured but no workspace is open.
*/
export function expandConfiguredPath(filePath: string, workspaceRoot?: string): string | undefined {
let expandedPath = filePath;

if (expandedPath.includes('${workspaceFolder}')) {
if (!workspaceRoot) {
return undefined;
}
expandedPath = expandedPath.replace(/\$\{workspaceFolder\}/g, workspaceRoot);
}

if (expandedPath.startsWith('~/') || expandedPath.startsWith('~\\')) {
expandedPath = path.join(os.homedir(), expandedPath.slice(2));
}

return expandedPath;
}

/**
* Safely resolve the Zenzic executable path with cross-platform fallback logic.
Expand All @@ -29,7 +50,7 @@ const MIN_CORE_VERSION = '0.26.0';
* 2. System $PATH
* 3. Standard user binary fallback directories (~/.local/bin, ~/.cargo/bin, ~/.uv/bin) via os.homedir()
*/
export async function resolveExecutablePath(cmd: string): Promise<string | undefined> {
export async function resolveExecutablePath(cmd: string, workspaceRoot?: string): Promise<string | undefined> {
const isWindows = process.platform === 'win32';
const exts = isWindows ? ['.exe', '.cmd', '.bat', ''] : [''];

Expand All @@ -45,8 +66,13 @@ export async function resolveExecutablePath(cmd: string): Promise<string | undef
return undefined;
};

if (path.isAbsolute(cmd) || cmd.includes(path.sep) || (isWindows && cmd.includes('/'))) {
return await checkPath(cmd);
const expandedCmd = expandConfiguredPath(cmd, workspaceRoot);
if (!expandedCmd) {
return undefined;
}

if (path.isAbsolute(expandedCmd) || expandedCmd.includes(path.sep) || (isWindows && expandedCmd.includes('/'))) {
return await checkPath(expandedCmd);
}

const home = os.homedir();
Expand All @@ -62,7 +88,7 @@ export async function resolveExecutablePath(cmd: string): Promise<string | undef
const searchDirs = [...systemPaths, ...fallbackPaths];
for (const dir of searchDirs) {
if (!dir) continue;
const fullPath = path.join(dir, cmd);
const fullPath = path.join(dir, expandedCmd);
const resolved = await checkPath(fullPath);
if (resolved) {
return resolved;
Expand Down Expand Up @@ -167,8 +193,9 @@ export async function activate(context: vscode.ExtensionContext) {
const startServer = async () => {
const config = vscode.workspace.getConfiguration('zenzic');
const executablePath = config.get<string>('executablePath') || 'zenzic';
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;

const resolvedPath = await resolveExecutablePath(executablePath);
const resolvedPath = await resolveExecutablePath(executablePath, workspaceRoot);

if (!resolvedPath) {
statusBarItem!.text = '$(error) Zenzic: Not Found';
Expand Down Expand Up @@ -339,7 +366,7 @@ export async function activate(context: vscode.ExtensionContext) {

const config = vscode.workspace.getConfiguration('zenzic');
const executablePath = config.get<string>('executablePath') || 'zenzic';
const resolvedPath = await resolveExecutablePath(executablePath);
const resolvedPath = await resolveExecutablePath(executablePath, workspaceRoot);

if (!resolvedPath) {
dqsStatusBarItem.text = '$(error) Zenzic DQS: Not Found';
Expand Down
Loading