@dreki-gg/pi-plan-mode 0.14.2 → 0.14.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# @dreki-gg/pi-plan-mode
|
|
2
2
|
|
|
3
|
+
## 0.14.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Proper markdown rendering in plan.html — fenced code blocks, inline code, bold, italic, links, and all heading levels.
|
|
8
|
+
|
|
9
|
+
## 0.14.4
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Remove task list widget entirely — plan.jsonl is the source of truth.
|
|
14
|
+
|
|
15
|
+
## 0.14.3
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- Only show task widget during active plan execution, not after exiting plan mode.
|
|
20
|
+
|
|
3
21
|
## 0.14.2
|
|
4
22
|
|
|
5
23
|
### Patch Changes
|
|
@@ -24,39 +24,83 @@ function markdownToHtml(markdown: string): string {
|
|
|
24
24
|
const lines = markdown.split(/\r?\n/);
|
|
25
25
|
const html: string[] = [];
|
|
26
26
|
let inList = false;
|
|
27
|
+
let inCode = false;
|
|
28
|
+
let codeLang = '';
|
|
29
|
+
const codeLines: string[] = [];
|
|
27
30
|
|
|
28
31
|
for (const line of lines) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
inList = false;
|
|
32
|
+
// Fenced code blocks
|
|
33
|
+
if (line.startsWith('```')) {
|
|
34
|
+
if (!inCode) {
|
|
35
|
+
if (inList) { html.push('</ul>'); inList = false; }
|
|
36
|
+
inCode = true;
|
|
37
|
+
codeLang = line.slice(3).trim();
|
|
38
|
+
codeLines.length = 0;
|
|
39
|
+
} else {
|
|
40
|
+
const langAttr = codeLang ? ` class="language-${escapeHtml(codeLang)}"` : '';
|
|
41
|
+
html.push(`<pre><code${langAttr}>${codeLines.map(escapeHtml).join('\n')}</code></pre>`);
|
|
42
|
+
inCode = false;
|
|
43
|
+
codeLang = '';
|
|
33
44
|
}
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
html.push('</ul>');
|
|
50
|
-
inList = false;
|
|
51
|
-
}
|
|
52
|
-
html.push(`<p>${escapeHtml(line)}</p>`);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (inCode) {
|
|
49
|
+
codeLines.push(line);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Headings
|
|
54
|
+
const headingMatch = line.match(/^(#{1,6})\s+(.*)$/);
|
|
55
|
+
if (headingMatch) {
|
|
56
|
+
if (inList) { html.push('</ul>'); inList = false; }
|
|
57
|
+
const level = headingMatch[1].length;
|
|
58
|
+
html.push(`<h${level}>${inlineMarkdown(escapeHtml(headingMatch[2]))}</h${level}>`);
|
|
59
|
+
continue;
|
|
53
60
|
}
|
|
61
|
+
|
|
62
|
+
// List items (- or *)
|
|
63
|
+
const listMatch = line.match(/^\s*[-*]\s+(.*)$/);
|
|
64
|
+
if (listMatch) {
|
|
65
|
+
if (!inList) { html.push('<ul>'); inList = true; }
|
|
66
|
+
html.push(`<li>${inlineMarkdown(escapeHtml(listMatch[1]))}</li>`);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Blank line
|
|
71
|
+
if (!line.trim()) {
|
|
72
|
+
if (inList) { html.push('</ul>'); inList = false; }
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Paragraph
|
|
77
|
+
if (inList) { html.push('</ul>'); inList = false; }
|
|
78
|
+
html.push(`<p>${inlineMarkdown(escapeHtml(line))}</p>`);
|
|
54
79
|
}
|
|
55
80
|
|
|
81
|
+
// Close unclosed blocks
|
|
82
|
+
if (inCode) {
|
|
83
|
+
html.push(`<pre><code>${codeLines.map(escapeHtml).join('\n')}</code></pre>`);
|
|
84
|
+
}
|
|
56
85
|
if (inList) html.push('</ul>');
|
|
57
86
|
return html.join('\n');
|
|
58
87
|
}
|
|
59
88
|
|
|
89
|
+
/** Converts inline markdown (bold, italic, inline code, links) in already-escaped HTML. */
|
|
90
|
+
function inlineMarkdown(text: string): string {
|
|
91
|
+
return text
|
|
92
|
+
// Inline code: `code`
|
|
93
|
+
.replace(/`([^`]+)`/g, '<code>$1</code>')
|
|
94
|
+
// Bold: **text** or __text__
|
|
95
|
+
.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
|
|
96
|
+
.replace(/__(.+?)__/g, '<strong>$1</strong>')
|
|
97
|
+
// Italic: *text* or _text_
|
|
98
|
+
.replace(/\*(.+?)\*/g, '<em>$1</em>')
|
|
99
|
+
.replace(/_(.+?)_/g, '<em>$1</em>')
|
|
100
|
+
// Links: [text](url)
|
|
101
|
+
.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2">$1</a>');
|
|
102
|
+
}
|
|
103
|
+
|
|
60
104
|
function escapeHtml(value: string): string {
|
|
61
105
|
return value
|
|
62
106
|
.replaceAll('&', '&')
|
|
@@ -17,6 +17,16 @@ html(lang="en")
|
|
|
17
17
|
section { background:rgba(17,20,27,0.82); border:1px solid var(--line); border-radius:18px; padding:22px; margin:18px 0; box-shadow:0 24px 80px rgba(0,0,0,0.24); }
|
|
18
18
|
.handoff :first-child { margin-top:0; }
|
|
19
19
|
.handoff :last-child { margin-bottom:0; }
|
|
20
|
+
.handoff pre { background:#161922; border:1px solid var(--line); border-radius:10px; padding:14px 16px; overflow-x:auto; margin:12px 0; }
|
|
21
|
+
.handoff pre code { font-family:ui-monospace, SFMono-Regular, Menlo, monospace; font-size:13px; color:#c7ccda; background:none; padding:0; border:none; border-radius:0; }
|
|
22
|
+
.handoff code { font-family:ui-monospace, SFMono-Regular, Menlo, monospace; font-size:13px; background:rgba(139,92,246,0.12); color:var(--accent); padding:2px 6px; border-radius:5px; }
|
|
23
|
+
.handoff strong { font-weight:650; }
|
|
24
|
+
.handoff a { color:var(--accent); text-decoration:none; }
|
|
25
|
+
.handoff a:hover { text-decoration:underline; }
|
|
26
|
+
.handoff h1, .handoff h3, .handoff h4 { font-size:15px; text-transform:uppercase; color:var(--muted); letter-spacing:0.14em; margin:20px 0 10px; }
|
|
27
|
+
.handoff p { margin:8px 0; }
|
|
28
|
+
.handoff ul { margin:8px 0; padding-left:20px; }
|
|
29
|
+
.handoff li { margin:4px 0; }
|
|
20
30
|
.tasks { display:grid; gap:12px; }
|
|
21
31
|
.task { border:1px solid var(--line); border-radius:14px; padding:16px; background:#0f1218; }
|
|
22
32
|
.task-top { display:flex; gap:10px; align-items:center; margin-bottom:8px; }
|
|
@@ -22,25 +22,6 @@ export function updateUI(state: PlanModeState, ctx: ExtensionContext): void {
|
|
|
22
22
|
ctx.ui.setStatus('plan-mode', undefined);
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if ((state.executing || state.plan) && state.plan && !allResolved) {
|
|
29
|
-
const lines = state.plan.tasks.map((task) => {
|
|
30
|
-
const label = `${task.id} ${task.description}`;
|
|
31
|
-
switch (task.status) {
|
|
32
|
-
case 'done':
|
|
33
|
-
return theme.fg('success', '✓ ') + theme.fg('muted', theme.strikethrough(label));
|
|
34
|
-
case 'skipped':
|
|
35
|
-
return theme.fg('warning', '⊘ ') + theme.fg('muted', theme.strikethrough(label));
|
|
36
|
-
case 'blocked':
|
|
37
|
-
return theme.fg('error', '✗ ') + theme.fg('error', label);
|
|
38
|
-
default:
|
|
39
|
-
return theme.fg('muted', '☐ ') + label;
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
ctx.ui.setWidget('plan-todos', lines);
|
|
43
|
-
} else {
|
|
44
|
-
ctx.ui.setWidget('plan-todos', undefined);
|
|
45
|
-
}
|
|
25
|
+
// Task list lives in plan.jsonl — no widget needed.
|
|
26
|
+
ctx.ui.setWidget('plan-todos', undefined);
|
|
46
27
|
}
|
package/package.json
CHANGED