@boyingliu01/opencode-plugin 0.8.11 → 0.8.13

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.
package/index.ts CHANGED
@@ -1,33 +1,68 @@
1
- /**
2
- * XP-Gate OpenCode Plugin
3
- *
4
- * Exposes 3 OpenCode tools that mirror the equivalent `xp-gate` CLI subcommands:
5
- * - gate-check: Run user-invokable quality gates (Gate 4 Principles + Gate 6 Arch) on a path
6
- * - gate-principles: Run Clean Code + SOLID principles checker (Gate 4 standalone)
7
- * - gate-arch: Run architecture validation (Gate 6 standalone)
8
- *
9
- * Dual-surface design (fixes #208): every tool is callable BOTH from inside an
10
- * OpenCode session (as these tools) AND from a plain shell (as `xp-gate check`,
11
- * `xp-gate principles`, `xp-gate arch`). The tools prefer the global `xp-gate`
12
- * CLI when available, but fall back to running the checker source directly via
13
- * `npx -y tsx` so they work even before `npm install -g @boyingliu01/xp-gate`.
14
- */
15
1
  import { tool } from "@opencode-ai/plugin"
16
2
  import { z } from "zod"
3
+ import { exec } from "child_process"
4
+ import { promisify } from "util"
5
+
6
+ const execAsync = promisify(exec)
17
7
 
18
8
  interface OpenCodePluginInput {
19
9
  directory: string
20
10
  $: (strings: TemplateStringsArray, ...values: unknown[]) => Promise<{ text(): Promise<string> }>
21
11
  }
22
12
 
13
+ /**
14
+ * Run a shell command via async exec, returning stdout or error message.
15
+ * Never throws — returns error string on failure.
16
+ */
17
+ async function runCmd(cmd: string, cwd: string): Promise<string> {
18
+ try {
19
+ const { stdout } = await execAsync(cmd, { cwd, timeout: 30000 })
20
+ return stdout || "[XP-Gate] Command completed (no output)."
21
+ } catch (err: any) {
22
+ if (err.stderr) return err.stderr
23
+ if (err.message) return `[XP-Gate] Error: ${err.message}`
24
+ return "[XP-Gate] Command failed."
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Check for xp-gate CLI availability and run a command via exec.
30
+ */
31
+ async function runXpGate(subcommand: string, cwd: string): Promise<string> {
32
+ // Check if xp-gate is on PATH
33
+ try {
34
+ await execAsync("command -v xp-gate", { cwd })
35
+ } catch {
36
+ return "" // CLI not available — caller should fall back
37
+ }
38
+ return runCmd(`xp-gate ${subcommand}`, cwd)
39
+ }
40
+
41
+ /**
42
+ * Check for a newer xp-gate version (non-blocking, advisory only).
43
+ */
44
+ async function getUpgradeSuggestion(cwd: string): Promise<string> {
45
+ try {
46
+ const result = await runXpGate("upgrade --preview", cwd)
47
+ if (!result) return ""
48
+ const parsed = JSON.parse(result)
49
+ if (parsed.outdated && parsed.remote) {
50
+ const releaseUrl = `https://github.com/boyingliu01/xp-gate/releases/tag/v${parsed.remote}`
51
+ return `[XP-Gate] New version v${parsed.remote} available (${releaseUrl}) — run: xp-gate upgrade`
52
+ }
53
+ return ""
54
+ } catch {
55
+ return ""
56
+ }
57
+ }
58
+
23
59
  export const XpGatePlugin = async (input: OpenCodePluginInput) => {
24
60
  const { directory, $ } = input
25
61
 
26
62
  return {
27
63
  tool: {
28
64
  "gate-check": tool({
29
- description:
30
- "Run xp-gate user-invokable quality gates (Gate 4 Principles + Gate 6 Architecture) on a file or directory. Prefers global xp-gate CLI; falls back to running checker source directly.",
65
+ description: "Run xp-gate quality gates (Gate 4 + Gate 6) on a file or directory. Prefers global xp-gate CLI; falls back to direct checker source.",
31
66
  args: {
32
67
  path: z.string().describe("File or directory path (absolute or relative to workspace)"),
33
68
  gates: z.array(z.string()).optional().describe("Optional gate subset (e.g. ['principles', 'arch'])"),
@@ -36,57 +71,50 @@ export const XpGatePlugin = async (input: OpenCodePluginInput) => {
36
71
  const cwd = ctx.directory || directory
37
72
  const target = args.path.startsWith("/") ? args.path : `${cwd}/${args.path}`
38
73
  const gatesFlag = args.gates?.length ? ` --gates ${args.gates.join(",")}` : ""
39
- // Prefer the installed xp-gate CLI. Fall back to invoking the same
40
- // subcommand source directly via npx tsx so the tool still works in
41
- // a fresh clone before `npm install -g @boyingliu01/xp-gate`.
42
- const cmd = `cd "${cwd}" && (command -v xp-gate >/dev/null 2>&1 && xp-gate check "${target}"${gatesFlag} || node ${directory}/src/npm-package/bin/xp-gate.js check "${target}"${gatesFlag})`
43
- try {
44
- const result = await $`bash -c ${cmd}`
45
- const text = await result.text()
46
- return text || "[XP-Gate] Check complete (no violations)."
47
- } catch (err) {
48
- return `[XP-Gate] gate-check failed.\nInstall xp-gate CLI: npm install -g @boyingliu01/xp-gate\n${err instanceof Error ? err.message : ""}`
74
+ const result = await runXpGate(`check "${target}"${gatesFlag}`, cwd)
75
+ if (result) {
76
+ const upgrade = await getUpgradeSuggestion(cwd)
77
+ return upgrade ? `${result}\n${upgrade}` : result
49
78
  }
79
+ // Fallback: invoke xp-gate source directly via node
80
+ const cmd = `node ${directory}/src/npm-package/bin/xp-gate.js check "${target}"${gatesFlag}`
81
+ return runCmd(cmd, cwd)
50
82
  },
51
83
  }),
52
84
  "gate-principles": tool({
53
- description:
54
- "Run Clean Code + SOLID principles checker (Gate 4 standalone) on a file or directory.",
85
+ description: "Run Clean Code + SOLID principles checker (Gate 4 standalone) on a file or directory.",
55
86
  args: {
56
87
  path: z.string().describe("Source file or directory path to check"),
57
88
  },
58
89
  async execute(args, ctx) {
59
90
  const cwd = ctx.directory || directory
60
91
  const target = args.path.startsWith("/") ? args.path : `${cwd}/${args.path}`
61
- // Try xp-gate CLI first, fall back to the principles source directly.
62
- const cmd = `cd "${cwd}" && (command -v xp-gate >/dev/null 2>&1 && xp-gate principles "${target}" || npx -y tsx ${directory}/src/principles/index.ts --files "${target}" --format console)`
63
- try {
64
- const result = await $`bash -c ${cmd}`
65
- const text = await result.text()
66
- return text || "[XP-Gate] Principles check complete (no violations)."
67
- } catch (err) {
68
- return `[XP-Gate] Principles checker failed.\nInstall xp-gate CLI: npm install -g @boyingliu01/xp-gate\n${err instanceof Error ? err.message : ""}`
92
+ const result = await runXpGate(`principles "${target}"`, cwd)
93
+ if (result) {
94
+ const upgrade = await getUpgradeSuggestion(cwd)
95
+ return upgrade ? `${result}\n${upgrade}` : result
69
96
  }
97
+ // Fallback: npx tsx on the principles source
98
+ const cmd = `npx -y tsx ${directory}/src/principles/index.ts --files "${target}" --format console`
99
+ return runCmd(cmd, cwd)
70
100
  },
71
101
  }),
72
102
  "gate-arch": tool({
73
- description:
74
- "Run architecture validation (Gate 6 standalone, layer boundary checks) on the repository.",
103
+ description: "Run architecture validation (Gate 6 standalone, layer boundary checks) on the repository.",
75
104
  args: {
76
105
  config: z.string().describe("Path to architecture config file").default("architecture.yaml"),
77
106
  },
78
107
  async execute(args, ctx) {
79
108
  const cwd = ctx.directory || directory
80
- // Prefer xp-gate CLI; fall back to @archlinter/cli directly so the tool
81
- // also works without xp-gate installed (matches gate-principles pattern).
82
- const cmd = `cd "${cwd}" && (command -v xp-gate >/dev/null 2>&1 && xp-gate arch --config ${args.config} || npx -y @archlinter/cli scan . --config ${args.config})`
83
- try {
84
- const result = await $`bash -c ${cmd}`
85
- const text = await result.text()
86
- return text || "[XP-Gate] Architecture check complete."
87
- } catch (err) {
88
- return `[XP-Gate] Architecture validation failed.\nRequires architecture.yaml in repo root.\nInstall xp-gate CLI: npm install -g @boyingliu01/xp-gate\n${err instanceof Error ? err.message : ""}`
109
+ const config = args.config || "architecture.yaml"
110
+ const result = await runXpGate(`arch --config ${config}`, cwd)
111
+ if (result) {
112
+ const upgrade = await getUpgradeSuggestion(cwd)
113
+ return upgrade ? `${result}\n${upgrade}` : result
89
114
  }
115
+ // Fallback: @archlinter/cli directly
116
+ const cmd = `npx -y @archlinter/cli scan . --config ${config}`
117
+ return runCmd(cmd, cwd)
90
118
  },
91
119
  }),
92
120
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boyingliu01/opencode-plugin",
3
- "version": "0.8.11",
3
+ "version": "0.8.13",
4
4
  "type": "module",
5
5
  "main": "index.ts",
6
6
  "description": "XP-Gate quality gates + AI workflow skills for OpenCode",
@@ -1,9 +1,9 @@
1
1
  # SKILLS/DELPHI-REVIEW KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-06-14
4
- **Commit:** 348c405
3
+ **Generated:** 2026-06-16
4
+ **Commit:** b1d8786
5
5
  **Branch:** main
6
- **Version:** 0.8.11.0
6
+ **Version:** 0.8.13.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Delphi Consensus Review — multi-round anonymous expert review (≥90% threshold, 3 experts from ≥2 providers, domestic models only). Supports design + code-walkthrough modes.
@@ -1,9 +1,9 @@
1
1
  # SKILLS/SPRINT-FLOW KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-06-14
4
- **Commit:** 348c405
3
+ **Generated:** 2026-06-16
4
+ **Commit:** b1d8786
5
5
  **Branch:** main
6
- **Version:** 0.8.11.0
6
+ **Version:** 0.8.13.0
7
7
 
8
8
  ## OVERVIEW
9
9
  **11-phase** development pipeline: ISOLATE → AUTO-ESTIMATE → THINK → PLAN → BUILD → REVIEW → USER ACCEPTANCE → FEEDBACK → SHIP → LAND → CLEANUP. Phase 2 default build mode is **ralph-loop** (REQ-level iteration, 40-67% token savings vs parallel). HARD-GATE in Phase 1: design must pass Delphi review (≥90% consensus) before any coding.
@@ -1,9 +1,9 @@
1
1
  # SKILLS/TEST-SPECIFICATION-ALIGNMENT KNOWLEDGE BASE
2
2
 
3
- **Generated:** 2026-06-14
4
- **Commit:** 348c405
3
+ **Generated:** 2026-06-16
4
+ **Commit:** b1d8786
5
5
  **Branch:** main
6
- **Version:** 0.8.11.0
6
+ **Version:** 0.8.13.0
7
7
 
8
8
  ## OVERVIEW
9
9
  Test-Specification Alignment Engine — two-stage validation ensuring tests accurately reflect requirements and design specs.