@fink-andreas/pi-linear-tools 0.7.1 → 0.7.2
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 +11 -0
- package/extensions/pi-linear-tools.js +54 -19
- package/package.json +2 -2
- package/src/shared.js +9 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v0.7.2 (2026-07-21)
|
|
4
|
+
|
|
5
|
+
Patch release for Pi package rename compatibility and terminal-safe fallback rendering.
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
- **Support renamed Pi packages**: The extension now supports both legacy `@mariozechner/*` imports and the current `@earendil-works/*` package scope, including globally installed Pi paths.
|
|
9
|
+
- **Prevent CJK fallback-rendering crashes**: Plain-text fallback output now truncates by terminal columns, preventing over-width lines from CJK/non-ASCII text and tabs from triggering Pi TUI's width guard.
|
|
10
|
+
|
|
11
|
+
### Tests
|
|
12
|
+
- Added fallback-renderer regression coverage for CJK text, tabs, unavailable Markdown dependencies, and Markdown rendering failures.
|
|
13
|
+
|
|
3
14
|
## v0.7.1 (2026-06-09)
|
|
4
15
|
|
|
5
16
|
Patch release for issue creation milestone assignment and configuration text cleanup.
|
|
@@ -12,7 +12,11 @@ async function importPiCodingAgent() {
|
|
|
12
12
|
try {
|
|
13
13
|
return await import('@mariozechner/pi-coding-agent');
|
|
14
14
|
} catch {
|
|
15
|
-
|
|
15
|
+
try {
|
|
16
|
+
return await import('@earendil-works/pi-coding-agent');
|
|
17
|
+
} catch {
|
|
18
|
+
return importFromPiRoot('dist/index.js');
|
|
19
|
+
}
|
|
16
20
|
}
|
|
17
21
|
}
|
|
18
22
|
|
|
@@ -20,8 +24,16 @@ async function importPiTui() {
|
|
|
20
24
|
try {
|
|
21
25
|
return await import('@mariozechner/pi-tui');
|
|
22
26
|
} catch {
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
try {
|
|
28
|
+
return await import('@earendil-works/pi-tui');
|
|
29
|
+
} catch {
|
|
30
|
+
// pi-tui is a dependency of pi-coding-agent and may be nested under it
|
|
31
|
+
try {
|
|
32
|
+
return await importFromPiRoot('node_modules/@mariozechner/pi-tui/dist/index.js');
|
|
33
|
+
} catch {
|
|
34
|
+
return importFromPiRoot('node_modules/@earendil-works/pi-tui/dist/index.js');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
25
37
|
}
|
|
26
38
|
}
|
|
27
39
|
|
|
@@ -602,33 +614,56 @@ async function executeToolSafely(operationLabel, operation, options = {}) {
|
|
|
602
614
|
}
|
|
603
615
|
}
|
|
604
616
|
|
|
605
|
-
|
|
617
|
+
// Conservative column width used only by the plain-text fallback renderer:
|
|
618
|
+
// printable ASCII counts as 1 column, tabs as 3 (matching pi-tui), and every
|
|
619
|
+
// other code point as 2. This overestimates narrow non-ASCII characters but
|
|
620
|
+
// never underestimates terminal display width, so rendered lines stay within
|
|
621
|
+
// the terminal width and pi-tui's over-width guard never fires.
|
|
622
|
+
function fallbackColumnWidth(codePoint) {
|
|
623
|
+
if (codePoint === 0x09) return 3;
|
|
624
|
+
return codePoint >= 0x20 && codePoint <= 0x7e ? 1 : 2;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
export function truncateLineToColumns(line, maxColumns) {
|
|
628
|
+
let columns = 0;
|
|
629
|
+
let end = 0;
|
|
630
|
+
for (const char of line) {
|
|
631
|
+
const width = fallbackColumnWidth(char.codePointAt(0));
|
|
632
|
+
if (columns + width > maxColumns) break;
|
|
633
|
+
columns += width;
|
|
634
|
+
end += char.length;
|
|
635
|
+
}
|
|
636
|
+
return line.slice(0, end);
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
export function createPlainTextFallbackRenderer(text) {
|
|
640
|
+
const lines = text.split('\n');
|
|
641
|
+
return {
|
|
642
|
+
render: (width) => lines.map((line) => (width ? truncateLineToColumns(line, width) : line)),
|
|
643
|
+
invalidate: () => {},
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
export function renderMarkdownResult(result, _options, _theme, renderer = { Markdown, Text, getMarkdownTheme }) {
|
|
606
648
|
const text = result.content?.[0]?.text || '';
|
|
649
|
+
const { Markdown: markdown, Text: textComponent, getMarkdownTheme: getTheme } = renderer;
|
|
607
650
|
|
|
608
651
|
// Fall back to plain text if markdown packages not available
|
|
609
|
-
if (!
|
|
610
|
-
|
|
611
|
-
return {
|
|
612
|
-
render: (width) => lines.map((line) => (width && line.length > width ? line.slice(0, width) : line)),
|
|
613
|
-
invalidate: () => {},
|
|
614
|
-
};
|
|
652
|
+
if (!markdown || !getTheme) {
|
|
653
|
+
return createPlainTextFallbackRenderer(text);
|
|
615
654
|
}
|
|
616
655
|
|
|
617
656
|
// Return Markdown component directly - the TUI will call its render() method
|
|
618
657
|
try {
|
|
619
|
-
const mdTheme =
|
|
620
|
-
return new
|
|
658
|
+
const mdTheme = getTheme();
|
|
659
|
+
return new markdown(text, 0, 0, mdTheme, _theme ? { color: (t) => _theme.fg('toolOutput', t) } : undefined);
|
|
621
660
|
} catch (error) {
|
|
622
661
|
// If markdown rendering fails for any reason, show a visible error so we can diagnose.
|
|
623
662
|
const msg = `[pi-linear-tools] Markdown render failed: ${String(error?.message || error)}`;
|
|
624
|
-
if (
|
|
625
|
-
return new
|
|
663
|
+
if (textComponent) {
|
|
664
|
+
return new textComponent((_theme ? _theme.fg('error', msg) : msg) + `\n\n` + text, 0, 0);
|
|
626
665
|
}
|
|
627
|
-
|
|
628
|
-
return {
|
|
629
|
-
render: (width) => lines.map((line) => (width && line.length > width ? line.slice(0, width) : line)),
|
|
630
|
-
invalidate: () => {},
|
|
631
|
-
};
|
|
666
|
+
return createPlainTextFallbackRenderer(msg + '\n\n' + text);
|
|
632
667
|
}
|
|
633
668
|
}
|
|
634
669
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fink-andreas/pi-linear-tools",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Pi extension with Linear SDK tools and configuration commands",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"scripts": {
|
|
29
29
|
"start": "node index.js",
|
|
30
|
-
"test": "node tests/test-package-manifest.js && node tests/test-extension-registration.js && node tests/test-issue-comment-result.js && node tests/test-issue-priority.js && node tests/test-settings.js && node tests/test-issue-download.js && node tests/test-api-usage-caching.js && node tests/test-issue-create-milestone.js && node tests/test-assignee-update.js && node tests/test-rate-limit-fallback-update.js && node tests/test-full-assignee-flow.js && node tests/test-branch-param.js && node tests/test-team-filter.js && node tests/test-project-crud.js && node tests/test-project-lifecycle.js && node tests/test-sync-doc.js && node tests/test-issue-activity.js",
|
|
30
|
+
"test": "node tests/test-package-manifest.js && node tests/test-extension-registration.js && node tests/test-render-fallback.js && node tests/test-issue-comment-result.js && node tests/test-issue-priority.js && node tests/test-settings.js && node tests/test-issue-download.js && node tests/test-api-usage-caching.js && node tests/test-issue-create-milestone.js && node tests/test-assignee-update.js && node tests/test-rate-limit-fallback-update.js && node tests/test-full-assignee-flow.js && node tests/test-branch-param.js && node tests/test-team-filter.js && node tests/test-project-crud.js && node tests/test-project-lifecycle.js && node tests/test-sync-doc.js && node tests/test-issue-activity.js",
|
|
31
31
|
"dev:sync-local-extension": "node scripts/dev-sync-local-extension.mjs",
|
|
32
32
|
"release:check": "npm test && npm pack --dry-run"
|
|
33
33
|
},
|
package/src/shared.js
CHANGED
|
@@ -18,7 +18,7 @@ export function isPiCodingAgentRoot(dir) {
|
|
|
18
18
|
if (!fs.existsSync(pkgPath)) return false;
|
|
19
19
|
try {
|
|
20
20
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
21
|
-
return pkg?.name === '@mariozechner/pi-coding-agent';
|
|
21
|
+
return pkg?.name === '@mariozechner/pi-coding-agent' || pkg?.name === '@earendil-works/pi-coding-agent';
|
|
22
22
|
} catch {
|
|
23
23
|
return false;
|
|
24
24
|
}
|
|
@@ -50,9 +50,11 @@ export function findPiCodingAgentRoot() {
|
|
|
50
50
|
{
|
|
51
51
|
const binDir = path.dirname(entry);
|
|
52
52
|
const prefix = path.resolve(binDir, '..');
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
for (const scope of ['@mariozechner', '@earendil-works']) {
|
|
54
|
+
const candidate = path.join(prefix, 'lib', 'node_modules', scope, 'pi-coding-agent');
|
|
55
|
+
if (isPiCodingAgentRoot(candidate)) {
|
|
56
|
+
return candidate;
|
|
57
|
+
}
|
|
56
58
|
}
|
|
57
59
|
}
|
|
58
60
|
|
|
@@ -60,6 +62,9 @@ export function findPiCodingAgentRoot() {
|
|
|
60
62
|
for (const candidate of [
|
|
61
63
|
'/usr/local/lib/node_modules/@mariozechner/pi-coding-agent',
|
|
62
64
|
'/usr/lib/node_modules/@mariozechner/pi-coding-agent',
|
|
65
|
+
'/usr/local/lib/node_modules/@earendil-works/pi-coding-agent',
|
|
66
|
+
'/usr/lib/node_modules/@earendil-works/pi-coding-agent',
|
|
67
|
+
'/opt/homebrew/lib/node_modules/@earendil-works/pi-coding-agent',
|
|
63
68
|
]) {
|
|
64
69
|
if (isPiCodingAgentRoot(candidate)) {
|
|
65
70
|
return candidate;
|