Add Sprints 46-59: governance, porting foundation, and language graduation prep (Steps 689-828)

Sprints 46-58 implement the cross-language porting foundation: language-to-IR
adapters, equivalence checking, gate validation, legacy ingestion, managed/dynamic
families, low-level/logic-actor semantics, debug workflow tooling, AST-native
family tools, Rust/CPP raising tools, system-level orchestration, query family,
and porting gates. Sprint 59 adds the governance layer (policy packs, review
boards, waiver packets, ambiguity triage, decision ledger) with the
whetstone_review_porting_decision MCP tool.

Also includes: sprint plans 46-130, MCP taskitem pipeline scripts,
CLAUDE.md, docs, and full test matrix (steps 689-828).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Bill
2026-02-22 13:18:10 -07:00
parent 84bdad8e9e
commit 1696b92bb8
403 changed files with 21166 additions and 79 deletions

View File

@@ -4,6 +4,124 @@
// Buffer, file, project, and session operations.
// Included from EditorState.h after the EditorState struct definition.
inline std::string detectLanguageFromPath(const std::string& path) {
std::filesystem::path p(path);
std::string ext = p.extension().string();
std::transform(ext.begin(), ext.end(), ext.begin(),
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
if (ext == ".py") return "python";
if (ext == ".cpp" || ext == ".cc" || ext == ".cxx" || ext == ".c" ||
ext == ".h" || ext == ".hpp" || ext == ".hh") return "cpp";
if (ext == ".el") return "elisp";
if (ext == ".js" || ext == ".mjs" || ext == ".cjs") return "javascript";
if (ext == ".ts" || ext == ".tsx") return "typescript";
if (ext == ".java") return "java";
if (ext == ".rs") return "rust";
if (ext == ".go") return "go";
if (ext == ".org") return "org";
if (ext == ".md" || ext == ".markdown") return "markdown";
if (ext == ".txt" || ext == ".rst") return "text";
if (ext == ".docx") return "text";
if (ext == ".json" || ext == ".yaml" || ext == ".yml" ||
ext == ".toml" || ext == ".xml" || ext == ".ini" ||
ext == ".cfg" || ext == ".conf") return "text";
return "text";
}
inline bool supportsStructuredMode(const std::string& language) {
return language == "python" || language == "cpp" || language == "elisp" ||
language == "javascript" || language == "typescript" ||
language == "java" || language == "rust" || language == "go";
}
inline std::string replaceAll(std::string s, const std::string& from, const std::string& to) {
if (from.empty()) return s;
size_t pos = 0;
while ((pos = s.find(from, pos)) != std::string::npos) {
s.replace(pos, from.size(), to);
pos += to.size();
}
return s;
}
inline std::string decodeXmlEntities(std::string s) {
s = replaceAll(std::move(s), "&lt;", "<");
s = replaceAll(std::move(s), "&gt;", ">");
s = replaceAll(std::move(s), "&amp;", "&");
s = replaceAll(std::move(s), "&quot;", "\"");
s = replaceAll(std::move(s), "&apos;", "'");
return s;
}
inline std::string shellSingleQuote(const std::string& path) {
std::string out;
out.reserve(path.size() + 8);
out.push_back('\'');
for (char c : path) {
if (c == '\'') out += "'\\''";
else out.push_back(c);
}
out.push_back('\'');
return out;
}
inline bool readDocxAsText(const std::string& path, std::string& outText, std::string& outError) {
outText.clear();
outError.clear();
#ifdef _WIN32
outError = "DOCX import is currently available on Linux/macOS builds only";
return false;
#else
std::string command = "unzip -p " + shellSingleQuote(path) + " word/document.xml 2>/dev/null";
FILE* pipe = popen(command.c_str(), "r");
if (!pipe) {
outError = "failed to run unzip";
return false;
}
char buffer[4096];
std::string xml;
while (fgets(buffer, sizeof(buffer), pipe)) {
xml += buffer;
}
int rc = pclose(pipe);
if (rc != 0 || xml.empty()) {
outError = "could not extract DOCX XML (is unzip installed?)";
return false;
}
xml = replaceAll(std::move(xml), "<w:tab/>", "\t");
xml = replaceAll(std::move(xml), "<w:br/>", "\n");
xml = replaceAll(std::move(xml), "<w:cr/>", "\n");
xml = replaceAll(std::move(xml), "</w:p>", "\n\n");
std::string plain;
plain.reserve(xml.size());
bool inTag = false;
for (char c : xml) {
if (c == '<') {
inTag = true;
continue;
}
if (c == '>') {
inTag = false;
continue;
}
if (!inTag) plain.push_back(c);
}
plain = decodeXmlEntities(std::move(plain));
while (plain.find("\n\n\n") != std::string::npos) {
plain = replaceAll(std::move(plain), "\n\n\n", "\n\n");
}
if (plain.empty()) {
outError = "DOCX contained no readable text";
return false;
}
outText = std::move(plain);
return true;
#endif
}
inline std::string EditorState::makeUntitledName() const {
if (!buffers.hasBuffer("(untitled)")) return "(untitled)";
int i = 1;
@@ -26,7 +144,7 @@ inline void EditorState::createBuffer(const std::string& path, const std::string
bool disableSyntaxHighlight,
bool deferAstSync) {
BufferManager::BufferMode effectiveMode = mode;
if (language == "org") effectiveMode = BufferManager::BufferMode::Text;
if (!supportsStructuredMode(language)) effectiveMode = BufferManager::BufferMode::Text;
if (buffers.hasBuffer(path)) {
buffers.switchToBuffer(path);
activeBuffer = bufferStates[path].get();
@@ -192,9 +310,17 @@ inline bool EditorState::loadProject(const std::string& path) {
closeAllBuffers();
if (!project.workspaceRoot.empty()) {
workspaceRoot = project.workspaceRoot;
fileTreeDirty = true;
search.projectSearch.setRoot(workspaceRoot);
std::string rootError;
if (!setWorkspaceRoot(project.workspaceRoot, &rootError)) {
notify(NotificationLevel::Warning,
"Project workspace is unavailable: " + rootError);
}
} else {
std::filesystem::path projectPath(path);
std::string parent = projectPath.parent_path().string();
if (!parent.empty()) {
setWorkspaceRoot(parent, nullptr);
}
}
std::string activePath = project.activePath;
@@ -282,9 +408,7 @@ inline bool EditorState::loadSession(SessionData& out) {
inline void EditorState::applySession(const SessionData& session) {
closeAllBuffers();
if (!session.workspaceRoot.empty()) {
workspaceRoot = session.workspaceRoot;
fileTreeDirty = true;
search.projectSearch.setRoot(workspaceRoot);
setWorkspaceRoot(session.workspaceRoot, nullptr);
}
ui.layoutPreset = LayoutManager::presetFromName(session.layoutPreset);
for (const auto& buf : session.buffers) {
@@ -365,36 +489,32 @@ inline void EditorState::doOpen(const std::string& path,
bool autoText = fileSizeBytes >= textBytes;
bool disableHighlight = fileSizeBytes >= disableHlBytes;
bool largeFileMode = disableHighlight;
const std::string language = detectLanguageFromPath(path);
BufferManager::BufferMode effectiveMode = modeOverride;
if (!supportsStructuredMode(language)) {
effectiveMode = BufferManager::BufferMode::Text;
}
if (autoText && modeOverride == BufferManager::BufferMode::Structured) {
effectiveMode = BufferManager::BufferMode::Text;
}
std::ifstream in(path);
if (in.is_open()) {
std::ostringstream ss;
ss << in.rdbuf();
std::string content = ss.str();
std::string language = "python";
if (path.size() > 3 && path.substr(path.size() - 3) == ".py")
language = "python";
else if (path.size() > 4 && path.substr(path.size() - 4) == ".cpp")
language = "cpp";
else if (path.size() > 2 && path.substr(path.size() - 2) == ".h")
language = "cpp";
else if (path.size() > 3 && path.substr(path.size() - 3) == ".el")
language = "elisp";
else if (path.size() > 3 && path.substr(path.size() - 3) == ".js")
language = "javascript";
else if (path.size() > 3 && path.substr(path.size() - 3) == ".ts")
language = "typescript";
else if (path.size() > 5 && path.substr(path.size() - 5) == ".java")
language = "java";
else if (path.size() > 3 && path.substr(path.size() - 3) == ".rs")
language = "rust";
else if (path.size() > 3 && path.substr(path.size() - 3) == ".go")
language = "go";
else if (path.size() > 4 && path.substr(path.size() - 4) == ".org")
language = "org";
std::string content;
bool opened = false;
std::string openError;
std::string ext = std::filesystem::path(path).extension().string();
std::transform(ext.begin(), ext.end(), ext.begin(),
[](unsigned char c) { return static_cast<char>(std::tolower(c)); });
if (ext == ".docx") {
opened = readDocxAsText(path, content, openError);
} else {
std::ifstream in(path);
if (in.is_open()) {
std::ostringstream ss;
ss << in.rdbuf();
content = ss.str();
opened = true;
}
}
if (opened) {
createBuffer(path, content, language, effectiveMode,
fileSizeBytes, largeFileMode, disableHighlight, deferAstSync);
welcome.addRecentFile(path, language, bufferModeToString(effectiveMode));
@@ -416,7 +536,8 @@ inline void EditorState::doOpen(const std::string& path,
{"sizeBytes", fileSizeBytes}
});
} else {
notify(NotificationLevel::Error, "Error opening: " + path);
notify(NotificationLevel::Error,
"Error opening: " + path + (openError.empty() ? "" : " (" + openError + ")"));
}
}
@@ -507,10 +628,52 @@ inline void EditorState::updateCursorPos(int bytePos) {
inline void EditorState::refreshFileTree() {
if (!fileTreeDirty) return;
fileTreeRoot = fileTree.build(workspaceRoot);
namespace fs = std::filesystem;
if (workspaceRoot.empty()) {
fileTreeRoot = FileNode{};
fileTreeDirty = false;
return;
}
std::error_code ec;
fs::path rootPath = fs::path(workspaceRoot);
if (!fs::exists(rootPath, ec) || !fs::is_directory(rootPath, ec)) {
fileTreeRoot = FileNode{};
fileTreeDirty = false;
return;
}
try {
fileTreeRoot = fileTree.build(rootPath.string());
} catch (...) {
fileTreeRoot = FileNode{};
}
fileTreeDirty = false;
}
inline bool EditorState::setWorkspaceRoot(const std::string& path, std::string* error) {
if (error) error->clear();
namespace fs = std::filesystem;
if (path.empty()) {
workspaceRoot.clear();
search.projectSearch.setRoot("");
fileTreeRoot = FileNode{};
fileTreeDirty = false;
return true;
}
std::error_code ec;
fs::path canonical = fs::weakly_canonical(fs::path(path), ec);
if (ec || !fs::exists(canonical, ec) || !fs::is_directory(canonical, ec)) {
if (error) *error = "invalid workspace path";
return false;
}
workspaceRoot = canonical.string();
fileTreeDirty = true;
search.projectSearch.setRoot(workspaceRoot);
refreshBuildSystem();
return true;
}
inline void EditorState::navigateToTarget(const NotificationTarget& target) {
if (target.path.empty()) return;
std::string path = target.path;