···11+// learning-opportunities-auto: OpenCode plugin
22+//
33+// Port of DrCatHicks/learning-opportunities' PostToolUse hook for OpenCode.
44+// After a git commit, injects a context message into the session that nudges
55+// the agent to consider offering a learning exercise via the skill.
66+//
77+// Zero external imports -- avoids Bun module resolution issues when deployed
88+// via Nix home-manager (where the file is copied from the Nix store).
99+//
1010+// License: CC-BY-4.0
1111+1212+export const LearningOpportunitiesAuto = async ({ client }) => {
1313+ let offers = 0;
1414+1515+ return {
1616+ "tool.execute.after": async (input, output) => {
1717+ // Only act on bash tool invocations
1818+ if (input.tool !== "bash") return;
1919+2020+ // Check if the command was a git commit
2121+ const command = input?.args?.command || "";
2222+ if (!/git\s+(commit|cz)/.test(command)) return;
2323+2424+ // Rate limit: max 2 offers per session
2525+ if (offers >= 2) return;
2626+ offers++;
2727+2828+ try {
2929+ // Inject a context message into the active session. The agent sees
3030+ // this as a user message with noReply, so it becomes part of the
3131+ // conversation context for the next assistant turn.
3232+ await client.session.prompt({
3333+ path: { id: input.sessionID },
3434+ body: {
3535+ noReply: true,
3636+ parts: [
3737+ {
3838+ type: "text",
3939+ text: [
4040+ "<system-reminder>",
4141+ "[learning-opportunities-auto] The user just committed code.",
4242+ "Per the learning-opportunities skill, consider whether this",
4343+ "is a good moment to offer a learning exercise. If the committed",
4444+ "work involved new files, schema changes, architectural decisions,",
4545+ "refactors, or unfamiliar patterns, ask the user (one short sentence)",
4646+ "if they'd like a 10-15 minute exercise. Do not start the exercise",
4747+ "until they confirm. If they decline, note it -- no more offers",
4848+ "this session.",
4949+ "</system-reminder>",
5050+ ].join(" "),
5151+ },
5252+ ],
5353+ },
5454+ });
5555+ } catch {
5656+ // Session prompt API may not be available in all contexts.
5757+ // Silently ignore -- the skill can always be invoked manually.
5858+ }
5959+ },
6060+ };
6161+};