Files
SuperCharged-Claude-Code-Up…/services/tag-parser.js
uroma 0dd2083556 Initial commit: Obsidian Web Interface for Claude Code
- Full IDE with terminal integration using xterm.js
- Session management with local and web sessions
- HTML preview functionality
- Multi-terminal support with session picker

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-19 16:29:44 +00:00

237 lines
5.4 KiB
JavaScript

/**
* Tag Parser for Dyad-style XML-like tags
* Extracts operations from LLM responses
*/
/**
* Parse all dyad-write tags from response
* Format: <dyad-write path="file.ext">content</dyad-write>
*/
function getDyadWriteTags(response) {
const tags = [];
const regex = /<dyad-write\s+path="([^"]+)">([\s\S]*?)<\/dyad-write>/g;
let match;
while ((match = regex.exec(response)) !== null) {
tags.push({
type: 'write',
path: match[1],
content: match[2].trim()
});
}
return tags;
}
/**
* Parse all dyad-rename tags from response
* Format: <dyad-rename from="old.ext" to="new.ext">
*/
function getDyadRenameTags(response) {
const tags = [];
const regex = /<dyad-rename\s+from="([^"]+)"\s+to="([^"]+)">/g;
let match;
while ((match = regex.exec(response)) !== null) {
tags.push({
type: 'rename',
from: match[1],
to: match[2]
});
}
return tags;
}
/**
* Parse all dyad-delete tags from response
* Format: <dyad-delete path="file.ext">
*/
function getDyadDeleteTags(response) {
const tags = [];
const regex = /<dyad-delete\s+path="([^"]+)">/g;
let match;
while ((match = regex.exec(response)) !== null) {
tags.push({
type: 'delete',
path: match[1]
});
}
return tags;
}
/**
* Parse all dyad-add-dependency tags from response
* Format: <dyad-add-dependency packages="pkg1 pkg2">
*/
function getDyadAddDependencyTags(response) {
const tags = [];
const regex = /<dyad-add-dependency\s+packages="([^"]+)">/g;
let match;
while ((match = regex.exec(response)) !== null) {
tags.push({
type: 'add-dependency',
packages: match[1].split(' ').filter(p => p.trim())
});
}
return tags;
}
/**
* Parse all dyad-command tags from response
* Format: <dyad-command type="rebuild|restart|refresh">
*/
function getDyadCommandTags(response) {
const tags = [];
const regex = /<dyad-command\s+type="([^"]+)">/g;
let match;
while ((match = regex.exec(response)) !== null) {
tags.push({
type: 'command',
command: match[1]
});
}
return tags;
}
/**
* Parse all dyad-chat-summary tags from response
* Format: <dyad-chat-summary>summary text</dyad-chat-summary>
*/
function getDyadChatSummary(response) {
const match = response.match(/<dyad-chat-summary>([\s\S]*?)<\/dyad-chat-summary>/);
if (match) {
return {
type: 'chat-summary',
summary: match[1].trim()
};
}
return null;
}
/**
* Extract all tags from response in order
* Returns structured object with all tag types
*/
function extractAllTags(response) {
return {
writes: getDyadWriteTags(response),
renames: getDyadRenameTags(response),
deletes: getDyadDeleteTags(response),
dependencies: getDyadAddDependencyTags(response),
commands: getDyadCommandTags(response),
chatSummary: getDyadChatSummary(response)
};
}
/**
* Check if response contains any actionable tags
*/
function hasActionableTags(response) {
const tags = extractAllTags(response);
return (
tags.writes.length > 0 ||
tags.renames.length > 0 ||
tags.deletes.length > 0 ||
tags.dependencies.length > 0 ||
tags.commands.length > 0
);
}
/**
* Strip all tags from response for display purposes
*/
function stripTags(response) {
let stripped = response;
// Remove dyad-write tags
stripped = stripped.replace(/<dyad-write\s+path="[^"]+">[\s\S]*?<\/dyad-write>/g, '[File operation]');
// Remove dyad-rename tags
stripped = stripped.replace(/<dyad-rename\s+from="[^"]+"\s+to="[^"]+">/g, '[Rename operation]');
// Remove dyad-delete tags
stripped = stripped.replace(/<dyad-delete\s+path="[^"]+">/g, '[Delete operation]');
// Remove dyad-add-dependency tags
stripped = stripped.replace(/<dyad-add-dependency\s+packages="[^"]+">/g, '[Install packages]');
// Remove dyad-command tags
stripped = stripped.replace(/<dyad-command\s+type="[^"]+">/g, '[Command]');
// Remove dyad-chat-summary tags
stripped = stripped.replace(/<dyad-chat-summary>[\s\S]*?<\/dyad-chat-summary>/g, '');
return stripped;
}
/**
* Generate a summary of operations for approval UI
*/
function generateOperationSummary(tags) {
const operations = [];
tags.deletes.forEach(tag => {
operations.push({
type: 'delete',
description: `Delete ${tag.path}`,
tag
});
});
tags.renames.forEach(tag => {
operations.push({
type: 'rename',
description: `Rename ${tag.from}${tag.to}`,
tag
});
});
tags.writes.forEach(tag => {
operations.push({
type: 'write',
description: `Create/update ${tag.path}`,
tag
});
});
tags.dependencies.forEach(tag => {
operations.push({
type: 'install',
description: `Install packages: ${tag.packages.join(', ')}`,
tag
});
});
tags.commands.forEach(tag => {
operations.push({
type: 'command',
description: `Execute command: ${tag.command}`,
tag
});
});
return operations;
}
module.exports = {
getDyadWriteTags,
getDyadRenameTags,
getDyadDeleteTags,
getDyadAddDependencyTags,
getDyadCommandTags,
getDyadChatSummary,
extractAllTags,
hasActionableTags,
stripTags,
generateOperationSummary
};