opencode-goal-plugin 0.6.1 → 0.6.3

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,160 +0,0 @@
1
- import assert from "node:assert/strict"
2
- import { execFileSync } from "node:child_process"
3
- import { mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises"
4
- import { tmpdir } from "node:os"
5
- import { join } from "node:path"
6
- import { pathToFileURL } from "node:url"
7
-
8
- const repository = new URL("..", import.meta.url)
9
- const root = await mkdtemp(join(tmpdir(), "opencode-goal-plugin-packed-host-"))
10
- const packDirectory = join(root, "pack")
11
- const projectDirectory = join(root, "host-project")
12
- const cacheDirectory = join(root, "npm-cache")
13
- const npmEnvironment = { ...process.env, npm_config_cache: cacheDirectory }
14
-
15
- try {
16
- await Promise.all([
17
- mkdir(packDirectory, { recursive: true }),
18
- mkdir(projectDirectory, { recursive: true }),
19
- mkdir(cacheDirectory, { recursive: true }),
20
- ])
21
- await writeFile(
22
- join(projectDirectory, "package.json"),
23
- JSON.stringify({ private: true, type: "module" }),
24
- )
25
-
26
- const packResult = JSON.parse(
27
- execFileSync(
28
- "npm",
29
- ["pack", "--json", "--pack-destination", packDirectory],
30
- { cwd: repository, encoding: "utf8", env: npmEnvironment },
31
- ),
32
- )
33
- assert.equal(packResult.length, 1)
34
- const tarball = join(packDirectory, packResult[0].filename)
35
-
36
- // Install only the artifact npm produced. The optional peer is omitted so this
37
- // contract test is offline-safe and cannot mutate the user's OpenCode install.
38
- execFileSync(
39
- "npm",
40
- [
41
- "install",
42
- "--ignore-scripts",
43
- "--no-audit",
44
- "--no-fund",
45
- "--no-package-lock",
46
- "--omit=peer",
47
- "--offline",
48
- "--cache",
49
- cacheDirectory,
50
- tarball,
51
- ],
52
- { cwd: projectDirectory, encoding: "utf8", env: npmEnvironment },
53
- )
54
-
55
- const installedManifestPath = join(
56
- projectDirectory,
57
- "node_modules",
58
- "opencode-goal-plugin",
59
- "package.json",
60
- )
61
- const installedManifest = JSON.parse(await readFile(installedManifestPath, "utf8"))
62
- const installedEntry = join(
63
- projectDirectory,
64
- "node_modules",
65
- "opencode-goal-plugin",
66
- installedManifest.main,
67
- )
68
- const installed = await import(pathToFileURL(installedEntry).href)
69
-
70
- assert.equal(installed.default.id, "opencode-goal-plugin")
71
- assert.equal(installed.default.server, installed.GoalPlugin)
72
-
73
- const sessionID = "packed-host-contract"
74
- const promptCalls = []
75
- const client = {
76
- app: { log: async () => {} },
77
- session: {
78
- messages: async ({ path }) => ({
79
- data: [
80
- {
81
- info: {
82
- id: "assistant-packed-contract",
83
- role: "assistant",
84
- sessionID: path.id,
85
- tokens: { input: 1, output: 1, reasoning: 0 },
86
- },
87
- parts: [{ type: "text", text: "Work remains." }],
88
- },
89
- ],
90
- }),
91
- promptAsync: async (input) => {
92
- promptCalls.push(input)
93
- return {}
94
- },
95
- },
96
- }
97
- const hooks = await installed.GoalPlugin(
98
- { client, directory: projectDirectory },
99
- {
100
- persistState: false,
101
- registerTools: false,
102
- minDelayMs: 1,
103
- noToolCallTurnsBeforePause: 10,
104
- },
105
- )
106
-
107
- for (const hook of [
108
- "config",
109
- "command.execute.before",
110
- "event",
111
- "experimental.chat.system.transform",
112
- "experimental.session.compacting",
113
- "experimental.compaction.autocontinue",
114
- "dispose",
115
- ]) {
116
- assert.equal(typeof hooks[hook], "function", `${hook} must be callable`)
117
- }
118
- const config = {}
119
- await hooks.config(config)
120
- assert.equal(config.agent.goal.mode, "primary")
121
- assert.equal(config.agent["goal-verify"].tools.edit, false)
122
-
123
- const output = { parts: [] }
124
- await hooks["command.execute.before"](
125
- { command: "goal", sessionID, arguments: "verify the installed artifact --max-turns 1" },
126
- output,
127
- )
128
- assert.match(output.parts[0]?.text, /New active goal/)
129
-
130
- // Let the configured throttle window elapse before idle. This avoids leaving
131
- // the contract dependent on the host's event-loop/timer shutdown behavior.
132
- await new Promise((resolve) => setTimeout(resolve, 5))
133
-
134
- await hooks.event({
135
- event: {
136
- type: "session.status",
137
- properties: { sessionID, status: { type: "idle" } },
138
- },
139
- })
140
-
141
- assert.equal(promptCalls.length, 1)
142
- // PluginInput currently supplies OpenCode's generated legacy client shape:
143
- // session.promptAsync({ path, body }). The standalone adapter suite covers
144
- // flattened v2 clients separately.
145
- assert.deepEqual(promptCalls[0].path, { id: sessionID })
146
- assert.equal(promptCalls[0].body.parts.length, 1)
147
- assert.deepEqual(promptCalls[0].body.parts[0].metadata, {
148
- "opencode-goal-plugin": { kind: "continuation" },
149
- })
150
- assert.equal(promptCalls[0].body.parts[0].synthetic, true)
151
-
152
- await hooks.dispose()
153
- await hooks.dispose()
154
-
155
- console.log(
156
- `packed host contract passed (${installedManifest.name}@${installedManifest.version}; ${packResult[0].size} byte tarball)`,
157
- )
158
- } finally {
159
- await rm(root, { recursive: true, force: true })
160
- }
@@ -1,51 +0,0 @@
1
- import assert from "node:assert/strict"
2
- import pluginModule, { GoalPlugin } from "opencode-goal-plugin"
3
-
4
- const sessionID = `smoke-${Date.now()}`
5
- const promptCalls = []
6
- const logCalls = []
7
-
8
- const client = {
9
- app: {
10
- log: async (input) => {
11
- logCalls.push(input)
12
- },
13
- },
14
- session: {
15
- messages: async () => ({ data: [] }),
16
- promptAsync: async (input) => {
17
- promptCalls.push(input)
18
- return {}
19
- },
20
- },
21
- }
22
-
23
- assert.equal(pluginModule.id, "opencode-goal-plugin")
24
- assert.equal(pluginModule.server, GoalPlugin)
25
-
26
- // persistState:false keeps the smoke test from reading or overwriting the
27
- // user's real ~/.opencode-goal-plugin/state.json.
28
- const hooks = await GoalPlugin({ client }, { minDelayMs: 1, persistState: false })
29
- assert.equal(typeof hooks["command.execute.before"], "function")
30
- assert.equal(typeof hooks.event, "function")
31
- assert.equal(typeof hooks["experimental.chat.system.transform"], "function")
32
-
33
- const commandHook = hooks["command.execute.before"]
34
-
35
- async function runGoalCommand(args) {
36
- const output = { parts: [] }
37
- await commandHook({ command: "goal", sessionID, arguments: args }, output)
38
- assert.equal(output.parts.length, 1)
39
- assert.equal(output.parts[0].type, "text")
40
- return output.parts[0].text
41
- }
42
-
43
- assert.match(await runGoalCommand("status"), /No active goal/)
44
- assert.match(await runGoalCommand("ship a smoke test --max-turns 1"), /New active goal/)
45
- assert.match(await runGoalCommand("status"), /Active goal: ship a smoke test/)
46
- assert.match(await runGoalCommand("clear"), /Goal cleared/)
47
- assert.match(await runGoalCommand("status"), /No active goal/)
48
- assert.equal(promptCalls.length, 0)
49
- assert.equal(logCalls.length, 0)
50
-
51
- console.log("opencode-goal-plugin command hook smoke passed")