@fink-andreas/pi-linear-tools 0.7.0 → 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 +34 -13
- package/extensions/pi-linear-tools.js +57 -22
- package/package.json +2 -2
- package/src/handlers.js +37 -59
- package/src/linear.js +11 -0
- package/src/shared.js +9 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,25 +1,46 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## v0.7.
|
|
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
|
+
|
|
14
|
+
## v0.7.1 (2026-06-09)
|
|
15
|
+
|
|
16
|
+
Patch release for issue creation milestone assignment and configuration text cleanup.
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
- **Fixed issue create milestone assignment**: `linear_issue create` now assigns project milestones when `milestone` or `projectMilestoneId` is provided.
|
|
20
|
+
- **Fixed configuration text typo**: Corrected config command/help text in the pi extension.
|
|
21
|
+
|
|
22
|
+
### Release Maintenance
|
|
23
|
+
- Updated package metadata to `0.7.1`.
|
|
24
|
+
|
|
25
|
+
## v0.7.0 (2026-06-09)
|
|
4
26
|
|
|
5
27
|
Issue image fetching and file download release.
|
|
6
28
|
|
|
7
29
|
### New Features
|
|
8
|
-
-
|
|
9
|
-
-
|
|
30
|
+
- **Issue image fetching**: Added `linear_issue(action="images")` to fetch embedded markdown/HTML images from issue descriptions and comments as tool image content.
|
|
31
|
+
- **Issue attachment downloads**: Added `linear_issue(action="download")` to download Linear issue attachments to validated local paths with filename sanitization and overwrite controls.
|
|
32
|
+
- **Workspace-wide issue listing**: `linear_issue list` can now list across the workspace without requiring a project context.
|
|
33
|
+
- **Overwrite configuration**: Added `allow_overwrite_files` config support via `/linear-tools-config` and `pi-linear-tools config`.
|
|
10
34
|
|
|
11
|
-
###
|
|
12
|
-
-
|
|
35
|
+
### Bug Fixes
|
|
36
|
+
- Fixed project archive mutation so `archiveProject` archives instead of deleting projects.
|
|
37
|
+
- Fixed comment rendering so submitted comment text appears in `linear_issue comment` results.
|
|
38
|
+
- Fixed rate-limit display to reflect actual complexity-based limits instead of a hardcoded total.
|
|
39
|
+
- Added project and project-update rate-limit pre-checks.
|
|
13
40
|
|
|
14
41
|
### Documentation
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
### Bug Fixes
|
|
18
|
-
- **Fixed workspace-wide issue listing (#4)**: `linear_issue list` now falls back to workspace-level listing (using `fetchIssues`) when no project is specified and cwd doesn't match a Linear project. This allows `linear_issue list assignee=me` to work without requiring a project context.
|
|
19
|
-
- Fixed project archive mutation to actually archive instead of delete (INN-301).
|
|
20
|
-
- Fixed `linear_issue comment` to render submitted comment text in result (INN-305).
|
|
21
|
-
- Fixed rate limit display to not show hardcoded total=5000 (INN-304).
|
|
22
|
-
- Fixed `linear_project` and `linear_project_update` to have rate-limit pre-check (INN-303).
|
|
42
|
+
- Added smoke test coverage for image and attachment workflows.
|
|
43
|
+
- Added dedicated release notes in `docs/RELEASE_NOTES_v0.7.0.md`.
|
|
23
44
|
|
|
24
45
|
## v0.6.0 (2026-04-23)
|
|
25
46
|
|
|
@@ -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
|
|
|
@@ -358,7 +370,7 @@ async function runInteractiveConfigFlow(ctx, pi) {
|
|
|
358
370
|
}
|
|
359
371
|
|
|
360
372
|
if (!client) {
|
|
361
|
-
const selectedAuthMethod = await ctx.ui.select('Select authentication method', ['API Key (recommended for full
|
|
373
|
+
const selectedAuthMethod = await ctx.ui.select('Select authentication method', ['API Key (recommended for full functionality)', 'OAuth']);
|
|
362
374
|
|
|
363
375
|
if (!selectedAuthMethod) {
|
|
364
376
|
ctx.ui.notify('Configuration cancelled', 'warning');
|
|
@@ -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
|
|
|
@@ -748,11 +783,11 @@ async function registerLinearTools(pi) {
|
|
|
748
783
|
},
|
|
749
784
|
milestone: {
|
|
750
785
|
type: 'string',
|
|
751
|
-
description: 'For update: milestone name/ID,
|
|
786
|
+
description: 'For create/update: milestone name/ID. For create, also provide project so names can be resolved. Use "none" to clear on update.',
|
|
752
787
|
},
|
|
753
788
|
projectMilestoneId: {
|
|
754
789
|
type: 'string',
|
|
755
|
-
description: 'Optional explicit milestone ID alias for update.',
|
|
790
|
+
description: 'Optional explicit milestone ID alias for create/update.',
|
|
756
791
|
},
|
|
757
792
|
subIssueOf: {
|
|
758
793
|
type: 'string',
|
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-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/handlers.js
CHANGED
|
@@ -25,7 +25,6 @@ import {
|
|
|
25
25
|
fetchIssueActivity,
|
|
26
26
|
formatIssueAsMarkdown,
|
|
27
27
|
formatIssueActivityAsMarkdown,
|
|
28
|
-
fetchIssues,
|
|
29
28
|
fetchIssuesByProject,
|
|
30
29
|
fetchProjectMilestones,
|
|
31
30
|
fetchMilestoneDetails,
|
|
@@ -390,24 +389,12 @@ async function startGitBranch(branchName, fromRef = 'HEAD', onBranchExists = 'sw
|
|
|
390
389
|
export async function executeIssueList(client, params) {
|
|
391
390
|
return withHandlerErrorHandling(async () => {
|
|
392
391
|
let projectRef = params.project;
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
if (projectRef) {
|
|
396
|
-
// Explicit project specified - use project-scoped listing
|
|
397
|
-
projectMode = true;
|
|
398
|
-
} else {
|
|
399
|
-
// No explicit project - try cwd fallback
|
|
400
|
-
const cwdProject = path.basename(process.cwd());
|
|
401
|
-
try {
|
|
402
|
-
const resolved = await resolveProjectRef(client, cwdProject);
|
|
403
|
-
projectRef = resolved.name; // use resolved name for display
|
|
404
|
-
projectMode = true;
|
|
405
|
-
} catch {
|
|
406
|
-
// cwd doesn't match any project - fall back to workspace-level listing
|
|
407
|
-
projectMode = false;
|
|
408
|
-
}
|
|
392
|
+
if (!projectRef) {
|
|
393
|
+
projectRef = path.basename(process.cwd());
|
|
409
394
|
}
|
|
410
395
|
|
|
396
|
+
const resolved = await resolveProjectRef(client, projectRef);
|
|
397
|
+
|
|
411
398
|
let assigneeId = null;
|
|
412
399
|
if (params.assignee === 'me') {
|
|
413
400
|
const viewer = await getViewer(client);
|
|
@@ -421,50 +408,21 @@ export async function executeIssueList(client, params) {
|
|
|
421
408
|
teamId = team.id;
|
|
422
409
|
}
|
|
423
410
|
|
|
424
|
-
const
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
let projectName = null;
|
|
430
|
-
|
|
431
|
-
if (projectMode) {
|
|
432
|
-
// Project-scoped listing
|
|
433
|
-
const resolved = await resolveProjectRef(client, projectRef);
|
|
434
|
-
projectId = resolved.id;
|
|
435
|
-
projectName = resolved.name;
|
|
436
|
-
|
|
437
|
-
const result = await fetchIssuesByProject(client, resolved.id, params.states || null, {
|
|
438
|
-
assigneeId,
|
|
439
|
-
teamId,
|
|
440
|
-
limit,
|
|
441
|
-
});
|
|
442
|
-
issues = result.issues;
|
|
443
|
-
truncated = result.truncated;
|
|
444
|
-
} else {
|
|
445
|
-
// Workspace-level listing (no project filter)
|
|
446
|
-
// Default to open states if none specified
|
|
447
|
-
const workspaceStates = params.states || ['Backlog', 'Triage', 'In Progress', 'In Review'];
|
|
448
|
-
const result = await fetchIssues(client, assigneeId, workspaceStates, limit);
|
|
449
|
-
issues = result.issues;
|
|
450
|
-
truncated = result.truncated;
|
|
451
|
-
}
|
|
411
|
+
const { issues, truncated } = await fetchIssuesByProject(client, resolved.id, params.states || null, {
|
|
412
|
+
assigneeId,
|
|
413
|
+
teamId,
|
|
414
|
+
limit: params.limit || 20,
|
|
415
|
+
});
|
|
452
416
|
|
|
453
417
|
if (issues.length === 0) {
|
|
454
|
-
return toTextResult(
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
projectId,
|
|
460
|
-
projectName,
|
|
461
|
-
issueCount: 0,
|
|
462
|
-
}
|
|
463
|
-
);
|
|
418
|
+
return toTextResult(`No issues found in project "${resolved.name}"`, {
|
|
419
|
+
projectId: resolved.id,
|
|
420
|
+
projectName: resolved.name,
|
|
421
|
+
issueCount: 0,
|
|
422
|
+
});
|
|
464
423
|
}
|
|
465
424
|
|
|
466
|
-
const
|
|
467
|
-
const lines = [`## Issues in ${scopeLabel} (${issues.length}${truncated ? '+' : ''})\n`];
|
|
425
|
+
const lines = [`## Issues in project "${resolved.name}" (${issues.length}${truncated ? '+' : ''})\n`];
|
|
468
426
|
|
|
469
427
|
for (const issue of issues) {
|
|
470
428
|
const stateLabel = issue.state?.name || 'Unknown';
|
|
@@ -484,8 +442,8 @@ export async function executeIssueList(client, params) {
|
|
|
484
442
|
}
|
|
485
443
|
|
|
486
444
|
return toTextResult(lines.join('\n'), {
|
|
487
|
-
projectId,
|
|
488
|
-
projectName,
|
|
445
|
+
projectId: resolved.id,
|
|
446
|
+
projectName: resolved.name,
|
|
489
447
|
issueCount: issues.length,
|
|
490
448
|
truncated,
|
|
491
449
|
});
|
|
@@ -732,6 +690,22 @@ export async function executeIssueCreate(client, params, options = {}) {
|
|
|
732
690
|
createInput.projectId = resolvedProject.id;
|
|
733
691
|
}
|
|
734
692
|
|
|
693
|
+
if (params.projectMilestoneId !== undefined && params.projectMilestoneId !== null) {
|
|
694
|
+
createInput.projectMilestoneId = params.projectMilestoneId;
|
|
695
|
+
} else if (params.milestone !== undefined && params.milestone !== null) {
|
|
696
|
+
const milestoneRef = String(params.milestone || '').trim();
|
|
697
|
+
const clearMilestoneValues = new Set(['', 'none', 'null', 'unassigned', 'clear']);
|
|
698
|
+
|
|
699
|
+
if (!clearMilestoneValues.has(milestoneRef.toLowerCase())) {
|
|
700
|
+
if (!resolvedProject?.id) {
|
|
701
|
+
throw new Error('Missing required field: project. Provide project when assigning milestone by name during issue create, or use projectMilestoneId.');
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
const milestone = await resolveMilestoneRef(client, milestoneRef, resolvedProject.id);
|
|
705
|
+
createInput.projectMilestoneId = milestone.id;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
735
709
|
const issue = await createIssue(client, createInput);
|
|
736
710
|
|
|
737
711
|
const identifier = issue.identifier || issue.id || 'unknown';
|
|
@@ -742,8 +716,11 @@ export async function executeIssueCreate(client, params, options = {}) {
|
|
|
742
716
|
const stateLabel = issue.state?.name || 'Unknown';
|
|
743
717
|
const assigneeLabel = issue.assignee?.displayName || 'Unassigned';
|
|
744
718
|
|
|
719
|
+
const milestoneLabel = issue.projectMilestone?.name || null;
|
|
720
|
+
|
|
745
721
|
const metaParts = [`Team: ${team.name}`, `Project: ${projectLabel}`, `State: ${stateLabel}`, `Assignee: ${assigneeLabel}`];
|
|
746
722
|
if (priorityLabel) metaParts.push(`Priority: ${priorityLabel}`);
|
|
723
|
+
if (milestoneLabel) metaParts.push(`Milestone: ${milestoneLabel}`);
|
|
747
724
|
|
|
748
725
|
return toTextResult(
|
|
749
726
|
`Created issue **${identifier}**: ${issue.title}\n${metaParts.join(' | ')}`,
|
|
@@ -755,6 +732,7 @@ export async function executeIssueCreate(client, params, options = {}) {
|
|
|
755
732
|
project: issue.project,
|
|
756
733
|
state: issue.state,
|
|
757
734
|
assignee: issue.assignee,
|
|
735
|
+
projectMilestone: issue.projectMilestone,
|
|
758
736
|
url: issue.url,
|
|
759
737
|
}
|
|
760
738
|
);
|
package/src/linear.js
CHANGED
|
@@ -3150,6 +3150,7 @@ export async function setIssueState(client, issueId, stateId) {
|
|
|
3150
3150
|
* @param {string} [input.projectId] - Project ID
|
|
3151
3151
|
* @param {number|string} [input.priority] - Issue priority: 0=None, 1=Urgent, 2=High, 3=Medium, 4=Low; or none/urgent/high/medium/low
|
|
3152
3152
|
* @param {string} [input.assigneeId] - Assignee ID
|
|
3153
|
+
* @param {string} [input.projectMilestoneId] - Project milestone ID
|
|
3153
3154
|
* @param {string} [input.parentId] - Parent issue ID for sub-issues
|
|
3154
3155
|
* @returns {Promise<Object>} Created issue
|
|
3155
3156
|
*/
|
|
@@ -3202,6 +3203,10 @@ export async function createIssue(client, input) {
|
|
|
3202
3203
|
createInput.stateId = input.stateId;
|
|
3203
3204
|
}
|
|
3204
3205
|
|
|
3206
|
+
if (input.projectMilestoneId !== undefined) {
|
|
3207
|
+
createInput.projectMilestoneId = input.projectMilestoneId;
|
|
3208
|
+
}
|
|
3209
|
+
|
|
3205
3210
|
if (getRawRequest(client)) {
|
|
3206
3211
|
const payload = await executeGraphQL(client, ISSUE_CREATE_MUTATION, { input: createInput });
|
|
3207
3212
|
if (!payload?.issueCreate?.success) {
|
|
@@ -3245,6 +3250,9 @@ export async function createIssue(client, input) {
|
|
|
3245
3250
|
state: null,
|
|
3246
3251
|
team: null,
|
|
3247
3252
|
project: null,
|
|
3253
|
+
projectMilestone: createInput.projectMilestoneId
|
|
3254
|
+
? { id: createInput.projectMilestoneId, name: 'Unknown' }
|
|
3255
|
+
: null,
|
|
3248
3256
|
assignee: null,
|
|
3249
3257
|
};
|
|
3250
3258
|
}
|
|
@@ -3259,6 +3267,9 @@ export async function createIssue(client, input) {
|
|
|
3259
3267
|
state: null,
|
|
3260
3268
|
team: null,
|
|
3261
3269
|
project: null,
|
|
3270
|
+
projectMilestone: createInput.projectMilestoneId
|
|
3271
|
+
? { id: createInput.projectMilestoneId, name: 'Unknown' }
|
|
3272
|
+
: null,
|
|
3262
3273
|
assignee: null,
|
|
3263
3274
|
};
|
|
3264
3275
|
}, 'createIssue');
|
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;
|