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
3 changes: 2 additions & 1 deletion README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Two behavioral gates run throughout:
| | Feature | One-liner |
|---|---|---|
| 🧭 | MPA Research Spine | Eight-step verifiable research thread |
| 🛣️ | Ten research routes | Course/case/policy/lit/design/fieldwork/data/thesis/defence |
| 🛣️ | Twelve task routes | Course, case, policy, literature, design, fieldwork, data, thesis, defence, and related tasks |
| 🔗 | Course-to-capstone reuse | Notes, cases, code become assets; re-verify before reuse |
| 🧠 | MPA knowledge ontology | Theory map + China governance contexts + thinking checklist |
| 🛡️ | Data before writing | Audit first, write second, never mask gaps |
Expand All @@ -83,6 +83,7 @@ $skillRoot = Join-Path $HOME '.agents\skills\mpa-skill'
```

Default config goes to `%APPDATA%\mpa-skill\config.json`. Does not modify Zotero database or Obsidian settings. Add `-WhatIf` to preview; run `Test-MpaEnvironment.ps1` to check your setup.
If the config file already exists, initialization stops and preserves it. Pass a new `-ConfigPath` to create another configuration.

### Update and uninstall

Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
| | 特性 | 一句话 |
|---|---|---|
| 🧭 | MPA Research Spine | 八步可核验研究主线,先识别缺口再动笔 |
| 🛣️ | 十条研究路由 | 课程/案例/政策/文献/设计/田野/数据/论文/答辩,按需组合 |
| 🛣️ | 十二条任务路由 | 课程、案例、政策、文献、设计、田野、数据、论文、答辩等,按需组合 |
| 🔗 | 课程→毕业复用 | 笔记、案例、代码可沉淀为研究资产,复用前回原始来源核验 |
| 🧠 | MPA 知识本体 | 理论地图 + 中国治理情境 + 思维清单 + 课程映射 |
| 🛡️ | 数据先于写作 | 先审计再写作,不靠改写掩盖缺口 |
Expand All @@ -83,6 +83,7 @@ $skillRoot = Join-Path $HOME '.agents\skills\mpa-skill'
```

默认配置写入 `%APPDATA%\mpa-skill\config.json`,不修改 Zotero 数据库或 Obsidian 设置。预览操作加 `-WhatIf`;检查环境用 `Test-MpaEnvironment.ps1`。
若配置文件已存在,初始化会停止并保留原文件;要创建另一套配置,请指定新的 `-ConfigPath`。

### 更新与卸载 (Update & Uninstall)

Expand Down
3 changes: 2 additions & 1 deletion ml-analysis/mpa_ml_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"""

import json, re, os, warnings
from pathlib import Path
warnings.filterwarnings("ignore")

import numpy as np
Expand All @@ -25,7 +26,7 @@
from scipy.stats import chi2

# ── paths ──
REPO = r"E:\CodexProjects\mpa-skill-public"
REPO = Path(__file__).resolve().parents[1]
OUT = os.path.join(REPO, "ml-analysis", "output")
os.makedirs(OUT, exist_ok=True)

Expand Down
12 changes: 11 additions & 1 deletion skills/mpa-skill/scripts/Initialize-MpaWorkspace.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ if ([string]::IsNullOrWhiteSpace($ConfigPath)) {
$ConfigPath = Join-Path $env:APPDATA 'mpa-skill\config.json'
}
$resolvedConfig = Resolve-FullPath $ConfigPath
if (Test-Path -LiteralPath $resolvedConfig) {
throw "ConfigPath already exists: $resolvedConfig. Choose another ConfigPath to preserve the existing configuration."
}

if ([string]::IsNullOrWhiteSpace($ZoteroExecutable)) {
$candidates = [System.Collections.Generic.List[string]]::new()
Expand Down Expand Up @@ -75,7 +78,14 @@ if (-not $WhatIf) {
[IO.Directory]::CreateDirectory($configDirectory) | Out-Null
$json = [pscustomobject]$paths | ConvertTo-Json
$utf8 = New-Object Text.UTF8Encoding($false)
[IO.File]::WriteAllText($resolvedConfig, $json + [Environment]::NewLine, $utf8)
$stream = [IO.File]::Open($resolvedConfig, [IO.FileMode]::CreateNew, [IO.FileAccess]::Write)
try {
$writer = New-Object IO.StreamWriter($stream, $utf8)
$writer.Write($json + [Environment]::NewLine)
Comment on lines +81 to +84

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Publish the config only after its write succeeds

If serialization or the stream write fails—for example because the disk fills—or the process is interrupted after CreateNew, the destination remains as an empty or partial file. The new early Test-Path check then rejects every subsequent initialization attempt at the default path, turning a transient failure into a persistent invalid configuration; write to a temporary sibling and atomically move it into place without overwriting the destination.

Useful? React with 👍 / 👎.

$writer.Dispose()
} finally {
$stream.Dispose()
}
}

[pscustomobject]@{
Expand Down
20 changes: 20 additions & 0 deletions tests/Test-WorkspaceScripts.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,26 @@ try {
Assert-True ($config.zotero_executable -ceq $zoteroPath) 'explicit Zotero executable was not preserved'
Assert-True ($result.ConfigPath -ceq [IO.Path]::GetFullPath($configPath)) 'initializer summary config path differs'

$originalConfig = [IO.File]::ReadAllBytes($configPath)
$secondWorkspace = Join-Path $testRoot 'SecondWorkspace'
$existingConfigRejected = $false
try {
$null = & $initializeScript -WorkspaceRoot $secondWorkspace -ConfigPath $configPath
} catch {
$existingConfigRejected = $true
}
Assert-True $existingConfigRejected 'existing config was silently replaced'
Assert-True (-not (Test-Path -LiteralPath $secondWorkspace)) 'existing config rejection created a workspace'
Assert-True ([Convert]::ToBase64String([IO.File]::ReadAllBytes($configPath)) -ceq [Convert]::ToBase64String($originalConfig)) 'existing config changed'

$whatIfRejected = $false
try {
$null = & $initializeScript -WorkspaceRoot $secondWorkspace -ConfigPath $configPath -WhatIf
} catch {
$whatIfRejected = $true
}
Assert-True $whatIfRejected 'WhatIf did not report existing config conflict'

$whatIfRoot = Join-Path $testRoot 'WhatIfWorkspace'
$whatIfConfig = Join-Path $isolatedAppData 'what-if.json'
$null = & $initializeScript -WorkspaceRoot $whatIfRoot -ConfigPath $whatIfConfig -WhatIf
Expand Down
Loading