@brainervirus/workit-opencode 0.6.0 → 0.6.1

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.
Files changed (2) hide show
  1. package/package.json +8 -8
  2. package/src/plugin.ts +59 -23
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-opencode",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "private": false,
5
5
  "description": "Workit OpenCode plugin (thin wrapper over @brainervirus/workit-core)",
6
- "license": "MIT",
7
6
  "keywords": [
8
- "opencode",
9
- "workflow",
7
+ "agent",
10
8
  "mcp",
11
- "agent"
9
+ "opencode",
10
+ "workflow"
12
11
  ],
13
12
  "bugs": {
14
13
  "url": "https://github.com/BrainerVirus/workit/issues"
15
14
  },
15
+ "license": "MIT",
16
16
  "repository": {
17
17
  "type": "git",
18
18
  "url": "https://github.com/BrainerVirus/workit.git"
@@ -26,12 +26,12 @@
26
26
  ".": "./src/plugin.ts",
27
27
  "./src/*": "./src/*"
28
28
  },
29
- "scripts": {
30
- "typecheck": "tsc --noEmit"
31
- },
32
29
  "publishConfig": {
33
30
  "access": "public"
34
31
  },
32
+ "scripts": {
33
+ "typecheck": "tsc --noEmit"
34
+ },
35
35
  "dependencies": {
36
36
  "@brainervirus/workit-core": "^0.4.0",
37
37
  "@opencode-ai/plugin": "1.17.7"
package/src/plugin.ts CHANGED
@@ -1,12 +1,45 @@
1
1
  import { existsSync, readFileSync } from "node:fs";
2
2
  import { createRequire } from "node:module";
3
3
  import path from "node:path";
4
- import { fileURLToPath } from "node:url";
5
4
  import type { Plugin } from "@opencode-ai/plugin";
6
5
 
7
- import { getWorkflowBootstrap, isWorkflowBootstrap } from "./bootstrap";
8
- import { REMINDER_TEXT, DETECTION_TEXT, DOC_DELIVERY_TEXT, DOC_RENDER_TEXT, SDD_REMINDER_TEXT, shouldInjectSddReminder, CONFIG_GUARD_TEXT, shouldInjectConfigGuard, shouldInjectDocRender, VERIFICATION_TEXT, TDD_TEXT, BRAINSTORM_TEXT, DEBUG_TEXT, REVIEW_RECEPTION_TEXT, shouldInjectVerification, shouldInjectTdd, shouldInjectBrainstorm, shouldInjectDebug, shouldInjectReviewReception, ISSUE_RAIL_TEXT, shouldInjectIssueRail } from "@brainervirus/workit-core/src/core/reminder";
9
- import { detectProseChoices, detectBacktickDocRefs, findActiveSubagentDrivenPlans, detectConfigGapError, detectRawDocDelivery, detectVerificationClaim, detectUntestedImplementation, detectImplementationWithoutDesign, detectFixWithoutRootCause, detectBlindReviewAcceptance, detectInstructionOption } from "@brainervirus/workit-core/src/core/detector";
6
+ import { getWorkflowBootstrap } from "./bootstrap";
7
+ import {
8
+ REMINDER_TEXT,
9
+ DETECTION_TEXT,
10
+ DOC_DELIVERY_TEXT,
11
+ DOC_RENDER_TEXT,
12
+ SDD_REMINDER_TEXT,
13
+ shouldInjectSddReminder,
14
+ CONFIG_GUARD_TEXT,
15
+ shouldInjectConfigGuard,
16
+ shouldInjectDocRender,
17
+ VERIFICATION_TEXT,
18
+ TDD_TEXT,
19
+ BRAINSTORM_TEXT,
20
+ DEBUG_TEXT,
21
+ REVIEW_RECEPTION_TEXT,
22
+ shouldInjectVerification,
23
+ shouldInjectTdd,
24
+ shouldInjectBrainstorm,
25
+ shouldInjectDebug,
26
+ shouldInjectReviewReception,
27
+ ISSUE_RAIL_TEXT,
28
+ shouldInjectIssueRail,
29
+ } from "@brainervirus/workit-core/src/core/reminder";
30
+ import {
31
+ detectProseChoices,
32
+ detectBacktickDocRefs,
33
+ findActiveSubagentDrivenPlans,
34
+ detectConfigGapError,
35
+ detectRawDocDelivery,
36
+ detectVerificationClaim,
37
+ detectUntestedImplementation,
38
+ detectImplementationWithoutDesign,
39
+ detectFixWithoutRootCause,
40
+ detectBlindReviewAcceptance,
41
+ detectInstructionOption,
42
+ } from "@brainervirus/workit-core/src/core/detector";
10
43
  import { createTools } from "@brainervirus/workit-core/src/tools";
11
44
  import { adaptPluginHandoffClient } from "@brainervirus/workit-core/src/tools/handoff";
12
45
  import { WorkflowStateStore } from "@brainervirus/workit-core/src/state";
@@ -41,16 +74,14 @@ const worktreeDenials = {
41
74
  "*git *worktree*": "deny",
42
75
  } as const;
43
76
 
44
- const withWorktreeDenials = (
45
- configuredPermission: unknown,
46
- ): MutablePermission => {
77
+ const withWorktreeDenials = (configuredPermission: unknown): MutablePermission => {
47
78
  const permission: MutablePermission =
48
79
  typeof configuredPermission === "string"
49
80
  ? { "*": configuredPermission as PermissionDecision }
50
81
  : { ...((configuredPermission ?? {}) as MutablePermission) };
51
82
  const bash = permission.bash;
52
83
  const bashRules: Record<string, PermissionDecision> =
53
- typeof bash === "string" ? { "*": bash } : { ...(bash ?? {}) };
84
+ typeof bash === "string" ? { "*": bash } : { ...bash };
54
85
  for (const pattern of Object.keys(worktreeDenials)) delete bashRules[pattern];
55
86
  permission.bash = { ...bashRules, ...worktreeDenials };
56
87
  return permission;
@@ -68,10 +99,7 @@ const plugin: Plugin = async ({ client }) => {
68
99
  for (const [name, description] of Object.entries(descriptions)) {
69
100
  config.command[name] = {
70
101
  description,
71
- template: readFileSync(
72
- path.join(root, "commands", `${name}.md`),
73
- "utf8",
74
- ).trim(),
102
+ template: readFileSync(path.join(root, "commands", `${name}.md`), "utf8").trim(),
75
103
  };
76
104
  }
77
105
  mutable.skills ??= {};
@@ -84,14 +112,10 @@ const plugin: Plugin = async ({ client }) => {
84
112
  }
85
113
  }
86
114
  // Current OpenCode accepts top-level shorthand before the installed SDK types do.
87
- config.permission = withWorktreeDenials(
88
- config.permission,
89
- ) as typeof config.permission;
115
+ config.permission = withWorktreeDenials(config.permission) as typeof config.permission;
90
116
  for (const agent of Object.values(config.agent ?? {})) {
91
117
  if (!agent) continue;
92
- agent.permission = withWorktreeDenials(
93
- agent.permission,
94
- ) as typeof agent.permission;
118
+ agent.permission = withWorktreeDenials(agent.permission) as typeof agent.permission;
95
119
  }
96
120
  },
97
121
  "experimental.session.compacting": async ({ sessionID }, output) => {
@@ -110,7 +134,8 @@ const plugin: Plugin = async ({ client }) => {
110
134
 
111
135
  // First turn only: full bootstrap anchored to the session's first user message
112
136
  if (firstUser?.parts.length) {
113
- const firstAnchor = firstUser.parts.find((part) => part.type === "text") ?? firstUser.parts[0];
137
+ const firstAnchor =
138
+ firstUser.parts.find((part) => part.type === "text") ?? firstUser.parts[0];
114
139
  const firstText = firstUser.parts
115
140
  .filter((part) => part.type === "text")
116
141
  .map((part) => (part as { text?: string }).text ?? "")
@@ -128,7 +153,8 @@ const plugin: Plugin = async ({ client }) => {
128
153
  }
129
154
 
130
155
  // Every turn: compact reminder anchored to the CURRENT user message (idempotent)
131
- const anchor = currentUser.parts.find((part) => part.type === "text") ?? currentUser.parts[0];
156
+ const anchor =
157
+ currentUser.parts.find((part) => part.type === "text") ?? currentUser.parts[0];
132
158
  const makePart = (text: string, tag = "r") => ({
133
159
  id: `${anchor.id}-${tag}${Date.now()}`,
134
160
  sessionID: anchor.sessionID,
@@ -157,7 +183,11 @@ const plugin: Plugin = async ({ client }) => {
157
183
  const usedQuestionTool = lastAssistant.parts.some(
158
184
  (p) => (p as { tool?: string }).tool === "question",
159
185
  );
160
- if (detectProseChoices(assistantText) && !usedQuestionTool && !currentText.includes("workflow-detection")) {
186
+ if (
187
+ detectProseChoices(assistantText) &&
188
+ !usedQuestionTool &&
189
+ !currentText.includes("workflow-detection")
190
+ ) {
161
191
  currentUser.parts.unshift(makePart(DETECTION_TEXT, "d"));
162
192
  }
163
193
  const docRefs = detectBacktickDocRefs(assistantText);
@@ -190,7 +220,10 @@ const plugin: Plugin = async ({ client }) => {
190
220
  currentUser.parts.unshift(makePart(TDD_TEXT, "tdd"));
191
221
  }
192
222
  // Every turn: brainstorm rail — implementation without a presented design (idempotent)
193
- if (detectImplementationWithoutDesign(assistantText) && shouldInjectBrainstorm(currentText)) {
223
+ if (
224
+ detectImplementationWithoutDesign(assistantText) &&
225
+ shouldInjectBrainstorm(currentText)
226
+ ) {
194
227
  currentUser.parts.unshift(makePart(BRAINSTORM_TEXT, "br"));
195
228
  }
196
229
  // Every turn: debugging rail — fixes without root-cause evidence (idempotent)
@@ -198,7 +231,10 @@ const plugin: Plugin = async ({ client }) => {
198
231
  currentUser.parts.unshift(makePart(DEBUG_TEXT, "db"));
199
232
  }
200
233
  // Every turn: review-reception rail — feedback accepted without verification (idempotent)
201
- if (detectBlindReviewAcceptance(assistantText) && shouldInjectReviewReception(currentText)) {
234
+ if (
235
+ detectBlindReviewAcceptance(assistantText) &&
236
+ shouldInjectReviewReception(currentText)
237
+ ) {
202
238
  currentUser.parts.unshift(makePart(REVIEW_RECEPTION_TEXT, "rc"));
203
239
  }
204
240