opencode-pilot 0.24.9 → 0.24.10
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.
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
class OpencodePilot < Formula
|
|
2
2
|
desc "Automation daemon for OpenCode - polls GitHub/Linear issues and spawns sessions"
|
|
3
3
|
homepage "https://github.com/athal7/opencode-pilot"
|
|
4
|
-
url "https://github.com/athal7/opencode-pilot/archive/refs/tags/v0.24.
|
|
5
|
-
sha256 "
|
|
4
|
+
url "https://github.com/athal7/opencode-pilot/archive/refs/tags/v0.24.9.tar.gz"
|
|
5
|
+
sha256 "b477a5677fb80456db3f4f6464dd2071d0efb56bdd29b8a8fc01e5d56638f588"
|
|
6
6
|
license "MIT"
|
|
7
7
|
|
|
8
8
|
depends_on "node"
|
package/package.json
CHANGED
package/service/actions.js
CHANGED
|
@@ -687,16 +687,17 @@ export async function findReusableSession(serverUrl, directory, options = {}) {
|
|
|
687
687
|
export async function createSessionViaApi(serverUrl, directory, prompt, options = {}) {
|
|
688
688
|
const fetchFn = options.fetch || fetch;
|
|
689
689
|
const headerTimeout = options.headerTimeout || HEADER_TIMEOUT_MS;
|
|
690
|
-
// Use project directory for session creation (determines projectID in OpenCode).
|
|
691
|
-
// The working directory (which may be a worktree) is used for messages/commands.
|
|
692
690
|
const projectDir = options.projectDirectory || directory;
|
|
693
691
|
|
|
694
692
|
let session = null;
|
|
695
693
|
|
|
696
694
|
try {
|
|
697
|
-
// Step 1: Create session
|
|
695
|
+
// Step 1: Create session with the working directory (may be a worktree).
|
|
696
|
+
// This sets the session's working directory so the agent operates in the
|
|
697
|
+
// correct location. For worktree sessions, the server may assign
|
|
698
|
+
// projectID 'global' since sandbox paths don't match project worktrees.
|
|
698
699
|
const sessionUrl = new URL('/session', serverUrl);
|
|
699
|
-
sessionUrl.searchParams.set('directory',
|
|
700
|
+
sessionUrl.searchParams.set('directory', directory);
|
|
700
701
|
|
|
701
702
|
const createResponse = await fetchFn(sessionUrl.toString(), {
|
|
702
703
|
method: 'POST',
|
|
@@ -712,14 +713,20 @@ export async function createSessionViaApi(serverUrl, directory, prompt, options
|
|
|
712
713
|
session = await createResponse.json();
|
|
713
714
|
debug(`createSessionViaApi: created session ${session.id} in ${directory}`);
|
|
714
715
|
|
|
715
|
-
// Step 2: Update session
|
|
716
|
-
|
|
716
|
+
// Step 2: Update session - always PATCH with project directory when it
|
|
717
|
+
// differs from the working directory (worktree case). This re-associates
|
|
718
|
+
// the session with the correct project so it appears in the UI.
|
|
719
|
+
// Also set the title if provided.
|
|
720
|
+
const needsProjectScoping = projectDir !== directory;
|
|
721
|
+
if (options.title || needsProjectScoping) {
|
|
717
722
|
const updateUrl = new URL(`/session/${session.id}`, serverUrl);
|
|
718
723
|
updateUrl.searchParams.set('directory', projectDir);
|
|
724
|
+
const patchBody = {};
|
|
725
|
+
if (options.title) patchBody.title = options.title;
|
|
719
726
|
await fetchFn(updateUrl.toString(), {
|
|
720
727
|
method: 'PATCH',
|
|
721
728
|
headers: { 'Content-Type': 'application/json' },
|
|
722
|
-
body: JSON.stringify(
|
|
729
|
+
body: JSON.stringify(patchBody),
|
|
723
730
|
});
|
|
724
731
|
}
|
|
725
732
|
|
|
@@ -564,9 +564,9 @@ describe("integration: worktree creation with worktree_name", () => {
|
|
|
564
564
|
assert.ok(worktreeCreateCalled, "Should create worktree when worktree_name is configured");
|
|
565
565
|
assert.strictEqual(createdWorktreeName, "pr-42", "Should expand worktree_name template");
|
|
566
566
|
assert.ok(sessionCreated, "Should create session");
|
|
567
|
-
// Session creation uses the
|
|
568
|
-
// The
|
|
569
|
-
assert.strictEqual(sessionDirectory, "/
|
|
567
|
+
// Session creation uses the worktree directory (sets working directory)
|
|
568
|
+
// The PATCH with project directory re-associates it with the correct project
|
|
569
|
+
assert.strictEqual(sessionDirectory, "/worktree/pr-42", "Session should be created in worktree directory");
|
|
570
570
|
});
|
|
571
571
|
|
|
572
572
|
it("reuses stored directory when reprocessing same item", async () => {
|
|
@@ -618,8 +618,8 @@ describe("integration: worktree creation with worktree_name", () => {
|
|
|
618
618
|
assert.ok(result.success, "Action should succeed");
|
|
619
619
|
// Should NOT create a new worktree since we have existing_directory
|
|
620
620
|
assert.strictEqual(worktreeCreateCalled, false, "Should NOT create new worktree when existing_directory provided");
|
|
621
|
-
// Session creation uses the
|
|
622
|
-
assert.strictEqual(sessionDirectory,
|
|
621
|
+
// Session creation uses the existing worktree directory (sets working directory)
|
|
622
|
+
assert.strictEqual(sessionDirectory, existingWorktreeDir, "Session should be created in existing worktree directory");
|
|
623
623
|
});
|
|
624
624
|
|
|
625
625
|
it("skips session reuse when working in a worktree", async () => {
|
|
@@ -631,6 +631,7 @@ describe("integration: worktree creation with worktree_name", () => {
|
|
|
631
631
|
let sessionListQueried = false;
|
|
632
632
|
let sessionCreated = false;
|
|
633
633
|
let sessionCreateDirectory = null;
|
|
634
|
+
let patchDirectory = null;
|
|
634
635
|
|
|
635
636
|
const existingWorktreeDir = "/worktree/calm-wizard";
|
|
636
637
|
|
|
@@ -654,7 +655,10 @@ describe("integration: worktree creation with worktree_name", () => {
|
|
|
654
655
|
sessionCreateDirectory = req.query?.directory;
|
|
655
656
|
return { body: { id: "ses_new" } };
|
|
656
657
|
},
|
|
657
|
-
"PATCH /session/ses_new": () =>
|
|
658
|
+
"PATCH /session/ses_new": (req) => {
|
|
659
|
+
patchDirectory = req.query?.directory;
|
|
660
|
+
return { body: {} };
|
|
661
|
+
},
|
|
658
662
|
"POST /session/ses_new/message": () => ({ body: { success: true } }),
|
|
659
663
|
"POST /session/ses_new/command": () => ({ body: { success: true } }),
|
|
660
664
|
});
|
|
@@ -674,10 +678,13 @@ describe("integration: worktree creation with worktree_name", () => {
|
|
|
674
678
|
// Should NOT query for existing sessions when in a worktree
|
|
675
679
|
assert.strictEqual(sessionListQueried, false,
|
|
676
680
|
"Should skip session reuse entirely when in a worktree");
|
|
677
|
-
// Should create a new session
|
|
681
|
+
// Should create a new session with the worktree directory (correct working dir)
|
|
678
682
|
assert.ok(sessionCreated, "Should create a new session");
|
|
679
|
-
assert.strictEqual(sessionCreateDirectory,
|
|
680
|
-
"
|
|
683
|
+
assert.strictEqual(sessionCreateDirectory, existingWorktreeDir,
|
|
684
|
+
"Session should be created in worktree directory");
|
|
685
|
+
// PATCH re-associates the session with the correct project
|
|
686
|
+
assert.strictEqual(patchDirectory, "/proj",
|
|
687
|
+
"PATCH should use project directory for correct project scoping");
|
|
681
688
|
});
|
|
682
689
|
});
|
|
683
690
|
|
|
@@ -981,9 +981,9 @@ Check for bugs and security issues.`;
|
|
|
981
981
|
// Should NOT call worktree endpoints when existing_directory is provided
|
|
982
982
|
assert.strictEqual(worktreeListCalled, false, 'Should NOT list worktrees');
|
|
983
983
|
assert.strictEqual(worktreeCreateCalled, false, 'Should NOT create worktree');
|
|
984
|
-
// Session creation uses
|
|
985
|
-
assert.strictEqual(sessionDirectory, '/data/
|
|
986
|
-
'Session creation should use
|
|
984
|
+
// Session creation uses the worktree directory (sets correct working directory)
|
|
985
|
+
assert.strictEqual(sessionDirectory, '/data/worktree/calm-wizard',
|
|
986
|
+
'Session creation should use worktree directory for correct working dir');
|
|
987
987
|
// Result directory is the worktree (where file operations happen)
|
|
988
988
|
assert.strictEqual(result.directory, '/data/worktree/calm-wizard',
|
|
989
989
|
'Result should include worktree directory');
|
|
@@ -1042,11 +1042,12 @@ Check for bugs and security issues.`;
|
|
|
1042
1042
|
assert.ok(messageUrl.includes('%2Fpath%2Fto%2Fproject'), 'Message URL should include encoded directory path');
|
|
1043
1043
|
});
|
|
1044
1044
|
|
|
1045
|
-
test('
|
|
1045
|
+
test('creates session with worktree directory, patches with project directory for scoping', async () => {
|
|
1046
1046
|
const { createSessionViaApi } = await import('../../service/actions.js');
|
|
1047
1047
|
|
|
1048
1048
|
const mockSessionId = 'ses_test_proj';
|
|
1049
1049
|
let createUrl = null;
|
|
1050
|
+
let patchUrl = null;
|
|
1050
1051
|
let messageUrl = null;
|
|
1051
1052
|
|
|
1052
1053
|
const mockFetch = async (url, opts) => {
|
|
@@ -1057,6 +1058,11 @@ Check for bugs and security issues.`;
|
|
|
1057
1058
|
return { ok: true, json: async () => ({ id: mockSessionId }) };
|
|
1058
1059
|
}
|
|
1059
1060
|
|
|
1061
|
+
if (urlObj.pathname.includes(`/session/${mockSessionId}`) && opts?.method === 'PATCH') {
|
|
1062
|
+
patchUrl = url;
|
|
1063
|
+
return { ok: true, json: async () => ({}) };
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1060
1066
|
if (urlObj.pathname.includes('/message') && opts?.method === 'POST') {
|
|
1061
1067
|
messageUrl = url;
|
|
1062
1068
|
return { ok: true, json: async () => ({ success: true }) };
|
|
@@ -1075,13 +1081,18 @@ Check for bugs and security issues.`;
|
|
|
1075
1081
|
}
|
|
1076
1082
|
);
|
|
1077
1083
|
|
|
1078
|
-
// Session creation should use the
|
|
1079
|
-
assert.ok(createUrl.includes('
|
|
1080
|
-
'Session creation should use
|
|
1081
|
-
assert.ok(
|
|
1082
|
-
'Session creation should
|
|
1084
|
+
// Session creation should use the worktree directory (sets working directory)
|
|
1085
|
+
assert.ok(createUrl.includes('worktree'),
|
|
1086
|
+
'Session creation should use the worktree path');
|
|
1087
|
+
assert.ok(createUrl.includes('pr-415'),
|
|
1088
|
+
'Session creation should use the worktree path');
|
|
1089
|
+
|
|
1090
|
+
// PATCH should use the project directory (re-associates with correct project)
|
|
1091
|
+
assert.ok(patchUrl, 'PATCH should be called for project scoping');
|
|
1092
|
+
assert.ok(patchUrl.includes('%2Fhome%2Fuser%2Fcode%2Fodin'),
|
|
1093
|
+
'PATCH should use projectDirectory for project scoping');
|
|
1083
1094
|
|
|
1084
|
-
// Message should use the working directory (
|
|
1095
|
+
// Message should use the working directory (worktree)
|
|
1085
1096
|
assert.ok(messageUrl.includes('worktree'),
|
|
1086
1097
|
'Message should use the worktree working directory');
|
|
1087
1098
|
assert.ok(messageUrl.includes('pr-415'),
|