parse method
Parses full channel markdown content into a Channel.
Implementation
Channel parse(String markdown) {
final lines = markdown.split('\n');
var id = '';
var status = ChannelStatus.open;
var createdAt = DateTime.now();
var participants = <String>[];
var prompt = '';
var loadedInstructions = <String>[];
var workingRules = <String>[];
var maxTurns = 8;
final messages = <ChannelMessage>[];
final decisions = <ChannelDecision>[];
var section = '';
var metadataBlock = false;
var inDecision = false;
var decisionStatus = '';
var decisionSummary = StringBuffer();
var decisionRationale = StringBuffer();
var decisionRisks = <String>[];
var decisionTests = <String>[];
var inRationale = false;
var inRisks = false;
var inTests = false;
for (var i = 0; i < lines.length; i++) {
final line = lines[i].trim();
if (line.startsWith('# Walki Channel:')) {
id = line.replaceFirst('# Walki Channel:', '').trim();
continue;
}
if (line == '## Metadata') {
metadataBlock = true;
continue;
}
if (line.startsWith('## ') && line != '## Metadata') {
if (metadataBlock) metadataBlock = false;
if (line.startsWith('## Decision:')) {
inDecision = true;
decisionStatus = line.replaceFirst('## Decision:', '').trim();
continue;
}
inDecision = false;
inRationale = false;
inRisks = false;
inTests = false;
final messageMatch = RegExp(
r'^##\s+(\d{4}-\d{2}-\d{2}T[^\s]+)\s+-\s+(\S+)\s+-\s+(\S+)',
).firstMatch(line);
if (messageMatch != null) {
section = 'message';
final timestamp = DateTime.parse(messageMatch[1]!);
final agent = messageMatch[2]!;
final kind = MessageKind.fromString(messageMatch[3]!);
var content = StringBuffer();
var endsWithOver = false;
final timestampHeaderRegex = RegExp(r'^##\s+\d{4}-\d{2}-\d{2}T');
for (var j = i + 1; j < lines.length; j++) {
final msgLine = lines[j].trim();
if (msgLine.startsWith('---') ||
timestampHeaderRegex.hasMatch(msgLine) ||
msgLine.startsWith('## Decision:') ||
msgLine == '## Metadata' ||
msgLine == '## User Prompt' ||
msgLine == '## Working Rules' ||
msgLine == '## Loaded Instructions') {
i = j - 1;
break;
}
if (msgLine == 'OVER') {
endsWithOver = true;
continue;
}
content.writeln(lines[j]);
}
messages.add(
ChannelMessage(
agent: agent,
kind: kind,
content: content.toString().trimRight(),
timestamp: timestamp,
endsWithOver: endsWithOver,
),
);
continue;
}
if (line == '## User Prompt') {
section = 'prompt';
continue;
}
if (line == '## Loaded Instructions') {
section = 'instructions';
continue;
}
if (line == '## Working Rules') {
section = 'rules';
continue;
}
continue;
}
if (metadataBlock && line.startsWith('- ')) {
final keyValue = line.substring(2);
final colonIndex = keyValue.indexOf(':');
if (colonIndex > 0) {
final key = keyValue.substring(0, colonIndex).trim();
final value = keyValue.substring(colonIndex + 1).trim();
switch (key) {
case 'id':
if (id.isEmpty) id = value;
case 'status':
status = ChannelStatus.fromString(value);
case 'created_at':
createdAt = DateTime.parse(value);
case 'participants':
participants = value.split(',').map((s) => s.trim()).toList();
case 'max_turns':
maxTurns = int.tryParse(value) ?? 8;
}
}
continue;
}
if (inDecision) {
if (line.startsWith('Rationale:') || line.startsWith('Rationale')) {
inRationale = true;
inRisks = false;
inTests = false;
final rest = line.replaceFirst(RegExp(r'^Rationale:?\s*'), '');
if (rest.isNotEmpty) decisionRationale.writeln(rest);
continue;
}
if (line.startsWith('Risks:') || line.startsWith('Risks')) {
inRationale = false;
inRisks = true;
inTests = false;
continue;
}
if (line.startsWith('Required tests:') ||
line.startsWith('Required tests')) {
inRationale = false;
inRisks = false;
inTests = true;
continue;
}
if (line.startsWith('- ')) {
final item = line.substring(2);
if (inRisks) {
decisionRisks.add(item);
} else if (inTests) {
decisionTests.add(item);
} else if (inRationale) {
decisionRationale.writeln(item);
}
continue;
}
if (line.isEmpty) continue;
if (line.startsWith('---')) {
decisions.add(
ChannelDecision(
status: decisionStatus,
summary: decisionSummary.toString().trimRight(),
rationale: decisionRationale.toString().trimRight(),
risks: decisionRisks,
requiredTests: decisionTests,
),
);
inDecision = false;
decisionStatus = '';
decisionSummary = StringBuffer();
decisionRationale = StringBuffer();
decisionRisks = [];
decisionTests = [];
continue;
}
decisionSummary.writeln(line);
continue;
}
if (section == 'prompt') {
if (line.isNotEmpty &&
!line.startsWith('##') &&
!line.startsWith('---')) {
prompt = line;
}
continue;
}
if (section == 'instructions') {
if (line.startsWith('- ') && line.length > 2) {
loadedInstructions.add(line.substring(2));
}
continue;
}
if (section == 'rules') {
if (line.startsWith('- ') && line.length > 2) {
workingRules.add(line.substring(2));
}
continue;
}
}
if (inDecision && decisionSummary.isNotEmpty) {
decisions.add(
ChannelDecision(
status: decisionStatus,
summary: decisionSummary.toString().trimRight(),
rationale: decisionRationale.toString().trimRight(),
risks: decisionRisks,
requiredTests: decisionTests,
),
);
}
return Channel(
id: id,
status: status,
createdAt: createdAt,
participants: participants,
prompt: prompt,
loadedInstructions: loadedInstructions,
workingRules: workingRules,
messages: messages,
decisions: decisions,
maxTurns: maxTurns,
);
}