opencode-pilot 0.24.6 → 0.24.7
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.6.tar.gz"
|
|
5
|
+
sha256 "60f487bfbe6209da3687d854b848b920791dde739046fd72bf75594d6e5e6163"
|
|
6
6
|
license "MIT"
|
|
7
7
|
|
|
8
8
|
depends_on "node"
|
package/package.json
CHANGED
package/service/actions.js
CHANGED
|
@@ -673,14 +673,11 @@ export async function findReusableSession(serverUrl, directory, options = {}) {
|
|
|
673
673
|
/**
|
|
674
674
|
* Create a session via the OpenCode HTTP API
|
|
675
675
|
*
|
|
676
|
-
* This is a workaround for the known issue where `opencode run --attach`
|
|
677
|
-
* doesn't support a --dir flag, causing sessions to run in the wrong directory
|
|
678
|
-
* when attached to a global server.
|
|
679
|
-
*
|
|
680
676
|
* @param {string} serverUrl - Server URL (e.g., "http://localhost:4096")
|
|
681
|
-
* @param {string} directory - Working directory for
|
|
677
|
+
* @param {string} directory - Working directory for file operations (may be a worktree)
|
|
682
678
|
* @param {string} prompt - The prompt/message to send
|
|
683
679
|
* @param {object} [options] - Options
|
|
680
|
+
* @param {string} [options.projectDirectory] - Project directory for session scoping (defaults to directory)
|
|
684
681
|
* @param {string} [options.title] - Session title
|
|
685
682
|
* @param {string} [options.agent] - Agent to use
|
|
686
683
|
* @param {string} [options.model] - Model to use
|
|
@@ -690,13 +687,16 @@ export async function findReusableSession(serverUrl, directory, options = {}) {
|
|
|
690
687
|
export async function createSessionViaApi(serverUrl, directory, prompt, options = {}) {
|
|
691
688
|
const fetchFn = options.fetch || fetch;
|
|
692
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
|
+
const projectDir = options.projectDirectory || directory;
|
|
693
693
|
|
|
694
694
|
let session = null;
|
|
695
695
|
|
|
696
696
|
try {
|
|
697
|
-
// Step 1: Create
|
|
697
|
+
// Step 1: Create session scoped to the project directory
|
|
698
698
|
const sessionUrl = new URL('/session', serverUrl);
|
|
699
|
-
sessionUrl.searchParams.set('directory',
|
|
699
|
+
sessionUrl.searchParams.set('directory', projectDir);
|
|
700
700
|
|
|
701
701
|
const createResponse = await fetchFn(sessionUrl.toString(), {
|
|
702
702
|
method: 'POST',
|
|
@@ -715,7 +715,7 @@ export async function createSessionViaApi(serverUrl, directory, prompt, options
|
|
|
715
715
|
// Step 2: Update session title if provided
|
|
716
716
|
if (options.title) {
|
|
717
717
|
const updateUrl = new URL(`/session/${session.id}`, serverUrl);
|
|
718
|
-
updateUrl.searchParams.set('directory',
|
|
718
|
+
updateUrl.searchParams.set('directory', projectDir);
|
|
719
719
|
await fetchFn(updateUrl.toString(), {
|
|
720
720
|
method: 'PATCH',
|
|
721
721
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -842,7 +842,7 @@ export async function createSessionViaApi(serverUrl, directory, prompt, options
|
|
|
842
842
|
* @param {object} [options] - Execution options
|
|
843
843
|
* @returns {Promise<object>} Result with command, success, sessionId, etc.
|
|
844
844
|
*/
|
|
845
|
-
async function executeInDirectory(serverUrl, cwd, item, config, options = {}) {
|
|
845
|
+
async function executeInDirectory(serverUrl, cwd, item, config, options = {}, projectDirectory = null) {
|
|
846
846
|
// Build prompt from template
|
|
847
847
|
const prompt = buildPromptFromTemplate(config.prompt || "default", item);
|
|
848
848
|
|
|
@@ -923,6 +923,7 @@ async function executeInDirectory(serverUrl, cwd, item, config, options = {}) {
|
|
|
923
923
|
}
|
|
924
924
|
|
|
925
925
|
const result = await createSessionViaApi(serverUrl, cwd, prompt, {
|
|
926
|
+
projectDirectory: projectDirectory || cwd,
|
|
926
927
|
title: sessionTitle,
|
|
927
928
|
agent: config.agent,
|
|
928
929
|
model: config.model,
|
|
@@ -986,7 +987,7 @@ export async function executeAction(item, config, options = {}) {
|
|
|
986
987
|
if (config.existing_directory) {
|
|
987
988
|
debug(`executeAction: using existing_directory=${config.existing_directory}`);
|
|
988
989
|
const cwd = expandPath(config.existing_directory);
|
|
989
|
-
return await executeInDirectory(serverUrl, cwd, item, config, options);
|
|
990
|
+
return await executeInDirectory(serverUrl, cwd, item, config, options, baseCwd);
|
|
990
991
|
}
|
|
991
992
|
|
|
992
993
|
// Resolve worktree directory if configured
|
|
@@ -1038,5 +1039,5 @@ export async function executeAction(item, config, options = {}) {
|
|
|
1038
1039
|
|
|
1039
1040
|
debug(`executeAction: using cwd=${cwd}`);
|
|
1040
1041
|
|
|
1041
|
-
return await executeInDirectory(serverUrl, cwd, item, config, options);
|
|
1042
|
+
return await executeInDirectory(serverUrl, cwd, item, config, options, baseCwd);
|
|
1042
1043
|
}
|
|
@@ -564,7 +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
|
-
|
|
567
|
+
// Session creation uses the project directory (for correct projectID scoping)
|
|
568
|
+
// The worktree path is used for messages/commands (file operations)
|
|
569
|
+
assert.strictEqual(sessionDirectory, "/proj", "Session should be scoped to project directory");
|
|
568
570
|
});
|
|
569
571
|
|
|
570
572
|
it("reuses stored directory when reprocessing same item", async () => {
|
|
@@ -616,8 +618,8 @@ describe("integration: worktree creation with worktree_name", () => {
|
|
|
616
618
|
assert.ok(result.success, "Action should succeed");
|
|
617
619
|
// Should NOT create a new worktree since we have existing_directory
|
|
618
620
|
assert.strictEqual(worktreeCreateCalled, false, "Should NOT create new worktree when existing_directory provided");
|
|
619
|
-
// Session
|
|
620
|
-
assert.strictEqual(sessionDirectory,
|
|
621
|
+
// Session creation uses the project directory (for correct projectID scoping)
|
|
622
|
+
assert.strictEqual(sessionDirectory, "/proj", "Session should be scoped to project directory");
|
|
621
623
|
});
|
|
622
624
|
});
|
|
623
625
|
|
|
@@ -981,11 +981,12 @@ 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
|
-
//
|
|
985
|
-
assert.strictEqual(sessionDirectory, '/data/
|
|
986
|
-
'
|
|
984
|
+
// Session creation uses project directory (for correct projectID scoping)
|
|
985
|
+
assert.strictEqual(sessionDirectory, '/data/proj',
|
|
986
|
+
'Session creation should use project directory, not worktree');
|
|
987
|
+
// Result directory is the worktree (where file operations happen)
|
|
987
988
|
assert.strictEqual(result.directory, '/data/worktree/calm-wizard',
|
|
988
|
-
'Result should include directory');
|
|
989
|
+
'Result should include worktree directory');
|
|
989
990
|
});
|
|
990
991
|
});
|
|
991
992
|
|
|
@@ -1041,6 +1042,52 @@ Check for bugs and security issues.`;
|
|
|
1041
1042
|
assert.ok(messageUrl.includes('%2Fpath%2Fto%2Fproject'), 'Message URL should include encoded directory path');
|
|
1042
1043
|
});
|
|
1043
1044
|
|
|
1045
|
+
test('uses projectDirectory for session creation, working directory for messages', async () => {
|
|
1046
|
+
const { createSessionViaApi } = await import('../../service/actions.js');
|
|
1047
|
+
|
|
1048
|
+
const mockSessionId = 'ses_test_proj';
|
|
1049
|
+
let createUrl = null;
|
|
1050
|
+
let messageUrl = null;
|
|
1051
|
+
|
|
1052
|
+
const mockFetch = async (url, opts) => {
|
|
1053
|
+
const urlObj = new URL(url);
|
|
1054
|
+
|
|
1055
|
+
if (urlObj.pathname === '/session' && opts?.method === 'POST') {
|
|
1056
|
+
createUrl = url;
|
|
1057
|
+
return { ok: true, json: async () => ({ id: mockSessionId }) };
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
if (urlObj.pathname.includes('/message') && opts?.method === 'POST') {
|
|
1061
|
+
messageUrl = url;
|
|
1062
|
+
return { ok: true, json: async () => ({ success: true }) };
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
return { ok: false, text: async () => 'Not found' };
|
|
1066
|
+
};
|
|
1067
|
+
|
|
1068
|
+
await createSessionViaApi(
|
|
1069
|
+
'http://localhost:4096',
|
|
1070
|
+
'/home/user/.local/share/opencode/worktree/abc123/pr-415',
|
|
1071
|
+
'Fix the bug',
|
|
1072
|
+
{
|
|
1073
|
+
fetch: mockFetch,
|
|
1074
|
+
projectDirectory: '/home/user/code/odin',
|
|
1075
|
+
}
|
|
1076
|
+
);
|
|
1077
|
+
|
|
1078
|
+
// Session creation should use the project directory (for correct projectID scoping)
|
|
1079
|
+
assert.ok(createUrl.includes('%2Fhome%2Fuser%2Fcode%2Fodin'),
|
|
1080
|
+
'Session creation should use projectDirectory');
|
|
1081
|
+
assert.ok(!createUrl.includes('worktree'),
|
|
1082
|
+
'Session creation should NOT use the worktree path');
|
|
1083
|
+
|
|
1084
|
+
// Message should use the working directory (for file operations in the worktree)
|
|
1085
|
+
assert.ok(messageUrl.includes('worktree'),
|
|
1086
|
+
'Message should use the worktree working directory');
|
|
1087
|
+
assert.ok(messageUrl.includes('pr-415'),
|
|
1088
|
+
'Message should use the worktree working directory');
|
|
1089
|
+
});
|
|
1090
|
+
|
|
1044
1091
|
test('handles session creation failure', async () => {
|
|
1045
1092
|
const { createSessionViaApi } = await import('../../service/actions.js');
|
|
1046
1093
|
|