Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,18 @@ systemd-inhibit --list

## Install

Add to your `opencode.json`:
The package supports both OpenCode v1 and v2. Use the configuration key for
the OpenCode version you run.

OpenCode v2:

```json
{
"plugins": ["opencode-wakelock"]
}
```

OpenCode v1:

```json
{
Expand Down
87 changes: 86 additions & 1 deletion index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import type { Plugin } from "@opencode-ai/plugin";
import type {
Context as PluginContextV2,
Plugin as PluginV2,
} from "@opencode/plugin/promise/plugin";
import {
existsSync,
mkdirSync,
Expand Down Expand Up @@ -305,4 +309,85 @@ const wakelockPlugin: Plugin = async ({ client }) => {
};
};

export default { id: "opencode-wakelock", server: wakelockPlugin };
const wakelockPluginV2: PluginV2 = {
id: "opencode-wakelock",
async setup(ctx: PluginContextV2) {
const platform = detectPlatform();
if (platform === null) return;

startupCleanup(platform);

const log: LogFn = async (level, message, extra) => {
const details = extra ? ` ${JSON.stringify(extra)}` : "";
const line = `[opencode-wakelock] ${message}${details}`;
if (level === "warn") console.warn(line);
else if (level === "debug") console.debug(line);
else console.info(line);
};
const waitingSessions = new Set<string>();

const watchUntilIdle = (sessionID: string) => {
if (waitingSessions.has(sessionID)) return;
waitingSessions.add(sessionID);
void ctx.session.wait({ sessionID })
.catch(() => undefined)
.finally(() => {
waitingSessions.delete(sessionID);
release(sessionID, platform);
});
};

// The context hook is the reliable point at which a v2 model dispatch is
// active. session.wait() follows it through every terminal path, including
// cases where the public lifecycle stream does not emit an idle event.
await ctx.session.hook("context", (request) => {
acquire(request.sessionID, platform, log);
watchUntilIdle(request.sessionID);
});

const controller = new AbortController();
const watcher = (async () => {
try {
for await (const event of ctx.event.subscribe({ signal: controller.signal })) {
const data = "data" in event && event.data && typeof event.data === "object"
? event.data as { sessionID?: string; status?: { type?: string } }
: undefined;
const sessionID = data?.sessionID;
if (!sessionID) continue;
if (event.type === "session.status" && data.status?.type === "busy") {
acquire(sessionID, platform, log);
watchUntilIdle(sessionID);
} else if (
event.type === "session.idle" ||
event.type === "session.execution.failed" ||
event.type === "session.execution.interrupted"
) {
waitingSessions.delete(sessionID);
release(sessionID, platform);
}
}
} catch (error) {
if (!controller.signal.aborted) {
await log("warn", "Event subscription stopped", {
error: error instanceof Error ? error.message : String(error),
});
}
}
})();

return async () => {
controller.abort();
await watcher;
for (const sessionID of getActiveSessions()) {
const filePath = `${SESSIONS_DIR}/${sessionID}`;
try {
if (Number(readFileSync(filePath, "utf8").trim()) === process.pid) {
release(sessionID, platform);
}
} catch {}
}
};
},
};

export default { ...wakelockPluginV2, server: wakelockPlugin };
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"prepack": "npm run build"
},
"devDependencies": {
"@opencode/plugin": "^2.0.3",
"@opencode-ai/plugin": "latest",
"bun-types": "latest",
"typescript": "7.0.2"
Expand Down
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"moduleResolution": "bundler",
"outDir": "dist",
"strict": true,
"skipLibCheck": true,
"types": ["bun-types"]
}
}