@jfrog/opencode-jfrog-plugin 0.0.3 → 0.0.4

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 (34) hide show
  1. package/README.md +105 -51
  2. package/dist/index.js +30 -240
  3. package/package.json +6 -6
  4. package/skills/jfrog/SKILL.md +529 -0
  5. package/skills/jfrog/assets/.gitkeep +0 -0
  6. package/skills/jfrog/references/apptrust-entities.md +154 -0
  7. package/skills/jfrog/references/artifactory-api-gaps.md +206 -0
  8. package/skills/jfrog/references/artifactory-aql-syntax.md +656 -0
  9. package/skills/jfrog/references/artifactory-entities.md +236 -0
  10. package/skills/jfrog/references/artifactory-operations.md +178 -0
  11. package/skills/jfrog/references/catalog-entities.md +219 -0
  12. package/skills/jfrog/references/general-bulk-operations-and-agent-patterns.md +93 -0
  13. package/skills/jfrog/references/general-parallel-execution.md +131 -0
  14. package/skills/jfrog/references/general-use-case-hints.md +27 -0
  15. package/skills/jfrog/references/jfrog-brand-html-report.md +98 -0
  16. package/skills/jfrog/references/jfrog-cli-install-upgrade.md +30 -0
  17. package/skills/jfrog/references/jfrog-entity-index.md +112 -0
  18. package/skills/jfrog/references/jfrog-login-flow.md +132 -0
  19. package/skills/jfrog/references/jfrog-url-references.md +51 -0
  20. package/skills/jfrog/references/onemodel-common-patterns.md +323 -0
  21. package/skills/jfrog/references/onemodel-graphql.md +446 -0
  22. package/skills/jfrog/references/onemodel-query-examples.md +753 -0
  23. package/skills/jfrog/references/platform-access-entities.md +200 -0
  24. package/skills/jfrog/references/platform-admin-api-gaps.md +164 -0
  25. package/skills/jfrog/references/platform-admin-operations.md +58 -0
  26. package/skills/jfrog/references/projects-api.md +241 -0
  27. package/skills/jfrog/references/release-lifecycle-entities.md +180 -0
  28. package/skills/jfrog/references/stored-packages-entities.md +165 -0
  29. package/skills/jfrog/references/xray-entities.md +740 -0
  30. package/skills/jfrog/scripts/check-environment.sh +224 -0
  31. package/skills/jfrog/scripts/jfrog-login-register-session.sh +84 -0
  32. package/skills/jfrog/scripts/jfrog-login-save-credentials.sh +128 -0
  33. package/skills/jfrog-package-safety-and-download/SKILL.md +275 -0
  34. package/sync-skills-vendor.json +5 -0
package/README.md CHANGED
@@ -1,82 +1,136 @@
1
1
  # opencode-jfrog-plugin
2
2
 
3
- JFrog Plugin for seamless integration to Opencode
4
- This plugin is intended for use by JFrog Customers also using Opencode.
3
+ JFrog integration for [OpenCode](https://opencode.ai/). The plugin ships the official JFrog
4
+ [Agent Skills](https://opencode.ai/docs/skills/) with the package and registers them with OpenCode at
5
+ load time, so JFrog capabilities are available to the agent out of the box.
5
6
 
6
- ## Prerequisites
7
- ### General:
8
- - [JFrog Platform](https://jfrog.com) installed
9
- - [Opencode](https://opencode.ai/) installed
7
+ ## What's included
8
+
9
+ The plugin bundles two canonical skills, vendored (pinned) from
10
+ [`jfrog/jfrog-skills`](https://github.com/jfrog/jfrog-skills) and committed under `skills/`:
10
11
 
11
- ### MCP Registry:
12
- - Access to the corporate JFrog Platform with the AI Catalog enabled.
13
- - A project with at least one allowed MCP server.
12
+ - **`jfrog`** — interact with the JFrog Platform via the JFrog CLI, MCP server, and REST/GraphQL APIs
13
+ (Artifactory, Xray, builds, permissions, projects, release lifecycle, advanced security, and more).
14
+ - **`jfrog-package-safety-and-download`** check package safety/curation status and download packages
15
+ through JFrog.
14
16
 
15
- ### Curation:
16
- - JFrog Enterprise+ or a Unified Security Bundle
17
- - Xray deployment
18
- - Curation configuration on the used remote repositories
17
+ The skills ship **with the plugin** (vendored and pinned). They are **not** downloaded at runtime, so
18
+ the plugin works offline and the skill set is reproducible for a given plugin version.
19
19
 
20
+ The plugin is **self-contained**: everything it needs is in the published npm tarball (`dist/` + the
21
+ vendored `skills/`). There are no runtime downloads and no dependency on `releases.jfrog.io` or any other
22
+ external artifact host.
23
+
24
+ ## Prerequisites
20
25
 
21
- > This is a Bun module created from the [bun-module](https://github.com/zenobi-us/bun-module) template
26
+ - A [JFrog Platform](https://jfrog.com) instance you can authenticate against.
27
+ - [OpenCode](https://opencode.ai/) installed (verified against OpenCode **1.17.7** and newer, which
28
+ honors `config.skills.paths` in object form).
29
+ - For running the skills at runtime, the following must be on your `PATH`:
30
+ - [`jf`](https://jfrog.com/getting-started-with-jfrog-cli/) (JFrog CLI), `jq`, and `curl`.
31
+ - A configured JFrog CLI server (e.g. via `jf login` / `jf config add`).
22
32
 
23
33
  ## Installation
24
- Add the opencode-jfrog-plugin into your opencode config.
25
- Preferably set the plugin globally for all their developers using the Opencode remote configuration, visit [opencode remote configuration](https://opencode.ai/docs/config/#remote) for more details.
26
34
 
27
- The plugin configuration looks like this:
28
- ```
29
- "plugin": [
30
- "@jfrog/opencode-jfrog-plugin@0.0.3"
31
- ],
35
+ The plugin is published to public npm as
36
+ [`@jfrog/opencode-jfrog-plugin`](https://www.npmjs.com/package/@jfrog/opencode-jfrog-plugin) and is
37
+ listed on the [OpenCode ecosystem page](https://opencode.ai/docs/ecosystem). OpenCode has no plugin
38
+ marketplace — you install by referencing the npm package in your OpenCode config.
39
+
40
+ Add the plugin to your OpenCode config (`opencode.json`):
41
+
42
+ ```json
43
+ {
44
+ "plugin": ["@jfrog/opencode-jfrog-plugin"]
45
+ }
32
46
  ```
33
47
 
34
- ## How this works
35
- Once opencode starts it runs the plugin. The plugin then:
36
- 1. Pulls a few base skills that allow the integration from the developer opencode instance into JFrog (can be found under `~/.config/opencode/skills`)
37
- 2. Pulls integration instructions adding LLM hints on how to integrate with JFrog (can be found under `<project-root>/.jfrog/instructions`)
38
- 3. Appends integration instructions into the runtime opencode config
48
+ OpenCode resolves the package from npm and loads it. To pin a specific version, use
49
+ `"@jfrog/opencode-jfrog-plugin@<version>"`; omitting the version tracks the latest release.
50
+
51
+ For an organization-wide rollout, set the plugin in OpenCode's
52
+ [remote configuration](https://opencode.ai/docs/config/#remote) so every developer gets it
53
+ automatically.
39
54
 
40
- Once the skills and instructions are set, every relevant task (package management, skills and MCP handling) is integrated into JFrog.
41
- Once the user tries to resolve dependencies, handle packages, install MCP servers, and pull a skill, the system will verify integration prerequisites (JFrog CLI is installed and configured and `<project-root>/.jfrog/local/package-managers.json` is available) and will perform the task using JFrog capabilities.
55
+ ## How it works
42
56
 
43
- While the skills run, they make sure that JFrog CLI is installed and configured, and that package managers are configured against the JFrog platform.
57
+ The plugin is intentionally **thin**. On load it:
44
58
 
45
- ## Usage
46
- Developers who get the plugin through their corporate opencode configuration, or add it manually into their device configuration will automatically get the JFrog integration up and are expected to be asked for completion of package management setup when needed.
59
+ 1. Resolves its bundled `skills/` directory (shipped inside the package).
60
+ 2. Registers that directory with OpenCode through the `config` hook by adding it to
61
+ `config.skills.paths`.
47
62
 
48
- This can be handled manually or when a task requires it.
49
- ### Manually
50
- Within opencode, type `/skills` and select the `jfrog-setup-package-managers` skill to complete package management and project setup.
51
- ### Automatically
52
- Within opencode, when tasks require a JFrog skill, the triggered skill will guide the user through the needed setup.
63
+ OpenCode then discovers the skills the same way it discovers any skill — they appear via the `skill`
64
+ tool and `/skills`, and the agent invokes them when relevant. There is no runtime download, unzip, or
65
+ network call on load.
53
66
 
54
- ### Integration setup artifacts
55
- LLM instructions are automatically created at `<project-root>/.jfrog/instructions`
56
- Package management mappings are created at `<project-root>/.jfrog/local/package-managers.json`
57
- Skills are created under `~/.config/opencode/skills`
67
+ ## Updating the bundled skills
68
+
69
+ The skills are vendored at a pinned version. Updating them is a build-time step and **requires a new
70
+ plugin release** (there are no runtime skill updates). See [VENDOR.md](./VENDOR.md) for the pin-bump
71
+ workflow (`mise run sync-skills`).
58
72
 
59
73
  ## Troubleshooting
60
- The JFrog plugin pulls a minimal set of JFrog integration skills and LLM instructions that allow for the integration. It also adds the instructions file into the opencode project configuration file.
61
- The plugin does not log by default, but allows debug logs for troubleshooting the JFrog setup process.
62
- To enable opencode-jfrog-plugin debug logging, run `export JFROG_DEBUG_LOGS=true` before running opencode.
74
+
75
+ The plugin does not log by default. To enable debug logging:
76
+
77
+ ```bash
78
+ export JFROG_DEBUG_LOGS=true
79
+ ```
80
+
81
+ Logs are written to `<project-root>/.opencode/event-log.txt`.
82
+
83
+ If you see a **"bundled skills not found"** error (a toast in the TUI and/or an `ERROR` line in the log),
84
+ the installed package is incomplete or corrupted — reinstall `@jfrog/opencode-jfrog-plugin`.
85
+
86
+ ## Upgrading from < 0.0.3
87
+
88
+ This release changes behavior in ways that are **not** backward compatible:
89
+
90
+ - **Skill catalog changed (7 → 2).** The previous Artifactory skills — `skill-install`,
91
+ `skill-publish`, `jfrog-cli`, `opencode-jfrog-mcp`, `jfrog-setup-package-managers`, `jfrog-curation`,
92
+ `jfrog-packages` — are replaced by the two canonical skills above. Invocations of the removed skill
93
+ names no longer exist; that functionality now folds into the `jfrog` skill.
94
+ - **Package-manager auto-setup was removed.** Earlier versions ran `jf setup <pm>` automatically on
95
+ session start. That is gone; the plugin now emits an interim one-line nudge to run
96
+ `jf setup <pm>` yourself. Durable package-manager setup is being recovered upstream in
97
+ `jfrog/jfrog-skills`.
98
+ - **Old skills are not auto-cleaned.** The plugin no longer touches `~/.config/opencode/skills`. If you
99
+ used a version < 0.0.3, remove the old managed skill directories yourself (e.g. `skill-install`,
100
+ `skill-publish`, `jfrog-cli`, `opencode-jfrog-mcp`, `jfrog-setup-package-managers`, `jfrog-curation`,
101
+ `jfrog-packages`) under `~/.config/opencode/skills`.
102
+ - **No more runtime artifacts.** The plugin no longer injects an instructions file
103
+ (`.jfrog/instructions/...`) or writes `.jfrog/local/package-managers.json`, and it no longer
104
+ downloads skills at runtime.
105
+ - **Dependencies resolve from public npm.** Internal registry references were removed; the build and CI
106
+ now resolve from public npm.
63
107
 
64
108
  ## Development
65
109
 
66
- - `mise run build` - Build the module
67
- - `mise run test` - Run tests
68
- - `mise run lint` - Lint code
69
- - `mise run lint:fix` - Fix linting issues
70
- - `mise run format` - Format code with Prettier
110
+ Tasks are run with [mise](https://mise.jdx.dev/):
111
+
112
+ - `mise run build` build the module
113
+ - `mise run test` run tests (`bun test`)
114
+ - `mise run typecheck` — type-check with `tsc --noEmit`
115
+ - `mise run lint` — lint with ESLint
116
+ - `mise run lint:fix` — auto-fix lint issues
117
+ - `mise run format` — format with Prettier
118
+ - `mise run sync-skills` — re-vendor the bundled skills (see [VENDOR.md](./VENDOR.md))
71
119
 
72
120
  ## Release
73
121
 
74
- See the [RELEASE.md](RELEASE.md) file for instructions on how to release a new version of the module.
122
+ See [RELEASE.md](./RELEASE.md) for how to release a new version.
75
123
 
76
124
  ## Contributing
77
125
 
78
- Contributions are welcome! Please file issues or submit pull requests on the GitHub repository.
126
+ Contributions are welcome! See [CONTRIBUTING.md](./CONTRIBUTING.md). Please file issues or open pull
127
+ requests on the GitHub repository.
79
128
 
80
129
  ## License
81
130
 
82
- See the [LICENSE](LICENSE) file for details.
131
+ See the [LICENSE](./LICENSE) file for details.
132
+
133
+ ## Compatibility
134
+
135
+ Verified against OpenCode **1.17.7** and newer (the first version confirmed to honor
136
+ `config.skills.paths` in object form). Older versions are not supported.
package/dist/index.js CHANGED
@@ -1,224 +1,21 @@
1
1
  // @bun
2
2
  // src/index.ts
3
- import {
4
- appendFileSync,
5
- createWriteStream,
6
- readFileSync,
7
- existsSync,
8
- mkdirSync,
9
- readdirSync,
10
- rmSync,
11
- statSync
12
- } from "fs";
13
- import { Readable } from "stream";
14
- import { pipeline } from "stream/promises";
3
+ import { appendFileSync, existsSync, mkdirSync, readdirSync, statSync } from "fs";
15
4
  import { dirname, join } from "path";
5
+ import { fileURLToPath } from "url";
16
6
  var LOG_FILE = join(process.cwd(), ".opencode", "event-log.txt");
17
- var SKILLS_REGISTRY_URL = "https://releases.jfrog.io/artifactory/jfrog-skills";
18
- var INSTRUCTIONS_REGISTRY_URL = "https://releases.jfrog.io/artifactory/run/ai/integrations/opencode/opencode-JFROG-INTEGRATION-MANAGEMENT-[RELEASE].md";
19
- var SKILLS_TO_INSTALL_URL = "https://releases.jfrog.io/artifactory/run/ai/integrations/opencode/opencode-JFROG-OPENCODE_SKILLS-[RELEASE].json";
20
- var fetchAndSaveFile = async (url, destPath, log) => {
21
- const dir = dirname(destPath);
22
- log("Fetching file from " + url + " and saving to " + destPath);
7
+ var BUNDLED_SKILLS_DIR = join(dirname(fileURLToPath(import.meta.url)), "..", "skills");
8
+ var isNonEmptyDir = (dir) => {
23
9
  if (!existsSync(dir)) {
24
- log("Creating skills directory: " + dir);
25
- mkdirSync(dir, { recursive: true });
10
+ return false;
26
11
  }
27
- const response = await fetch(url);
28
- if (!response.ok || !response.body) {
29
- log(`Failed to fetch file from ${url}, status: ${response.status}, No response body from ${url}, response: ${JSON.stringify(response)}`);
30
- return { success: false, error: `No response body from ${url}` };
31
- }
32
- const writer = createWriteStream(destPath);
33
- await pipeline(Readable.fromWeb(response.body), writer);
34
- return { success: true, error: undefined };
35
- };
36
- var extractZip = async ($, skillZipFile, skillName, skillVersion, skillZipDir, log) => {
37
- const unzipResponse = await $`unzip -o ${skillZipFile} -d ${skillZipDir}`.nothrow().quiet();
38
- if (unzipResponse.exitCode !== 0) {
39
- log(`Failed to extract JFrog ${skillName} skill: ${unzipResponse.stderr}`);
40
- return {
41
- success: false,
42
- error: `Failed to extract JFrog ${skillName}-${skillVersion} skill: ${unzipResponse.stderr}`
43
- };
44
- }
45
- log(`JFrog ${skillName}-${skillVersion} skill extracted!`);
46
- await $`rm -fR ${skillZipFile}`;
47
- log(`Jfrog ${skillName} skill zip file removed!`);
48
- return { success: true };
49
- };
50
- var setupPackageManagers = async (client, $, directory, sessionId, log) => {
51
- let jfVersion;
52
12
  try {
53
- jfVersion = await $`jf --version`.nothrow().quiet();
54
- } catch (e) {
55
- log("jf version command threw: " + e);
56
- return {
57
- success: false,
58
- message: "Jfrog cli is not installed, please use the jfrog-cli skill to install it"
59
- };
60
- }
61
- if (!jfVersion || jfVersion.exitCode !== 0) {
62
- log("jf version command failed");
63
- return {
64
- success: false,
65
- message: "Jfrog cli is not installed, please use the jfrog-cli skill to install it"
66
- };
67
- }
68
- const packageManagersFile = join(directory, ".jfrog", "local", "package-managers.json");
69
- if (!existsSync(packageManagersFile)) {
70
- return {
71
- success: false,
72
- message: "Jfrog packages are not setup, please use the jfrog-setup-package-managers skill to complete setup. type /skill and select jfrog-setup-package-managers"
73
- };
74
- }
75
- const packageManagersConfig = JSON.parse(readFileSync(packageManagersFile, "utf8"));
76
- const configuredPackageManagers = packageManagersConfig.configuredPackageManagers;
77
- if (!configuredPackageManagers) {
78
- return {
79
- success: false,
80
- message: "Jfrog packages are not setup, please use the jfrog-setup-package-managers skill to complete setup. type /skill and select jfrog-cli"
81
- };
82
- }
83
- const results = { success: [], error: [] };
84
- for (const packageManager in configuredPackageManagers) {
85
- const packageManagerConfig = configuredPackageManagers[packageManager];
86
- const result = await $`jf setup ${packageManager} --server-id ${packageManagerConfig.serverId} --repo ${packageManagerConfig.repository}`.nothrow().quiet();
87
- if (result.exitCode !== 0) {
88
- results.error.push({ packageManager, error: result.stderr });
89
- } else {
90
- results.success.push({ packageManager });
91
- }
13
+ return statSync(dir).isDirectory() && readdirSync(dir).length > 0;
14
+ } catch {
15
+ return false;
92
16
  }
93
- var errorMessages = "";
94
- if (results.error.length > 0) {
95
- errorMessages = "Failed to configure package managers:" + results.error.map((e) => e.packageManager + " - " + e.error).join(", ");
96
- }
97
- var successMessages = "";
98
- if (results.success.length > 0) {
99
- successMessages = "Package managers configured successfully:" + results.success.map((s) => s.packageManager).join(", ");
100
- }
101
- var success = true;
102
- if (results.error.length > 0) {
103
- success = false;
104
- }
105
- log("return message=" + errorMessages + successMessages);
106
- return { success, message: errorMessages + " " + successMessages };
107
17
  };
108
- var pullSkills = async ($, directory, log) => {
109
- const failedSkills = [];
110
- const jfroginstructionExists = await $`test -f ${directory}/.jfrog/instructions/JFROG-INTEGRATION-MANAGEMENT.md`.nothrow().quiet();
111
- if (jfroginstructionExists.exitCode !== 0) {
112
- log("JFrog integration management instructions not found, importing them locally!");
113
- const result = await fetchAndSaveFile(`${INSTRUCTIONS_REGISTRY_URL}`, `${directory}/.jfrog/instructions/JFROG-INTEGRATION-MANAGEMENT.md`, log);
114
- if (!result.success) {
115
- log(`Failed to import JFrog integration management instructions for Opencode: ${result.error}`);
116
- failedSkills.push("JFROG-INTEGRATION-MANAGEMENT");
117
- }
118
- log("JFrog integration management instructions imported!");
119
- }
120
- const response = await fetch(SKILLS_TO_INSTALL_URL);
121
- if (!response.body) {
122
- log(`Failed to fetch base skills list from ${SKILLS_TO_INSTALL_URL}, No response body from ${SKILLS_TO_INSTALL_URL}`);
123
- return {
124
- success: false,
125
- failedSkills: [
126
- `ALL Skills failed to fetch, No response body from ${SKILLS_TO_INSTALL_URL}, cannot install skills`
127
- ]
128
- };
129
- }
130
- const skillsBody = await response.json();
131
- if (!skillsBody.skills) {
132
- log(`Failed to fetch base skills list from ${SKILLS_TO_INSTALL_URL}, No skills body from ${SKILLS_TO_INSTALL_URL}`);
133
- return {
134
- success: false,
135
- failedSkills: [
136
- `ALL Skills failed to fetch, No skills body from ${SKILLS_TO_INSTALL_URL}, cannot install skills`
137
- ]
138
- };
139
- }
140
- const skillsToPull = skillsBody.skills.map((skill) => ({
141
- name: skill.name,
142
- version: skill.version
143
- }));
144
- log(`HOME: ${process.env.HOME}`);
145
- const skillsDir = join(process.env.HOME || "~", ".config", "opencode", "skills");
146
- if (!existsSync(skillsDir)) {
147
- mkdirSync(skillsDir, { recursive: true });
148
- log(`Skills directory created: ${skillsDir}`);
149
- }
150
- for (const skill of skillsToPull) {
151
- const keepVersion = String(skill.version).trim();
152
- const skillInstallDir = join(skillsDir, skill.name, keepVersion);
153
- const skillExists = existsSync(skillInstallDir) && statSync(skillInstallDir).isDirectory();
154
- if (!skillExists) {
155
- log(`JFrog ${skill.name}-${keepVersion} skill not found, importing them locally!`);
156
- const skillName = skill.name;
157
- const skillVersion = keepVersion;
158
- const skillZipDir = join(skillsDir, skillName, skillVersion);
159
- const skillZipFile = join(skillZipDir, `${skillName}-${skillVersion}.zip`);
160
- const result = await fetchAndSaveFile(`${SKILLS_REGISTRY_URL}/${skillName}/${skillVersion}/${skillName}-${skillVersion}.zip`, `${skillZipFile}`, log);
161
- if (!result.success) {
162
- log("Failed to import JFrog mcp skill: " + result.error);
163
- failedSkills.push(skillName);
164
- } else {
165
- const unzipResult = await extractZip($, skillZipFile, skillName, skillVersion, skillZipDir, log);
166
- if (!unzipResult.success) {
167
- log(`Failed to extract ${skillName} skill: ${unzipResult.error}`);
168
- failedSkills.push(skillName);
169
- } else {
170
- log(`${skillName} skill handling completed!`);
171
- pruneNonManifestSkillVersions(skillsDir, skillName, keepVersion, log);
172
- }
173
- }
174
- } else {
175
- log(`JFrog ${skill.name}-${keepVersion} skill already present.`);
176
- }
177
- }
178
- if (failedSkills.length > 0) {
179
- return { success: false, failedSkills };
180
- } else {
181
- return { success: true };
182
- }
183
- };
184
- var pruneNonManifestSkillVersions = (skillsDir, skillName, keepVersion, log) => {
185
- const skillRoot = join(skillsDir, skillName);
186
- if (!existsSync(skillRoot)) {
187
- log(`No local version dirs for ${skillName} under ${skillRoot}`);
188
- return;
189
- }
190
- let entries;
191
- try {
192
- entries = readdirSync(skillRoot);
193
- } catch (e) {
194
- log(`Could not list versions under ${skillRoot}: ${e}`);
195
- return;
196
- }
197
- log(`Found version dirs for ${skillName}: ${entries.join(", ")} (latest version: ${keepVersion})`);
198
- for (const olderVersion of entries) {
199
- const versionPath = join(skillRoot, olderVersion);
200
- let isDir = false;
201
- try {
202
- isDir = statSync(versionPath).isDirectory();
203
- } catch {
204
- continue;
205
- }
206
- if (!isDir) {
207
- continue;
208
- }
209
- if (olderVersion === keepVersion) {
210
- continue;
211
- }
212
- log(`Removing non-manifest version ${olderVersion} of ${skillName} (manifest: ${keepVersion})...`);
213
- try {
214
- rmSync(versionPath, { recursive: true, force: true });
215
- log(`Removed ${skillName}/${olderVersion}`);
216
- } catch (e) {
217
- log(`Failed to remove ${skillName}/${olderVersion}: ${e}`);
218
- }
219
- }
220
- };
221
- var jfrogOpencodePlugin = async ({ client, $, directory }) => {
18
+ var jfrogOpencodePlugin = async ({ client }) => {
222
19
  const logDir = dirname(LOG_FILE);
223
20
  if (!existsSync(logDir)) {
224
21
  mkdirSync(logDir, { recursive: true });
@@ -229,38 +26,31 @@ var jfrogOpencodePlugin = async ({ client, $, directory }) => {
229
26
  `, "utf-8");
230
27
  }
231
28
  };
29
+ const toast = (message, variant) => {
30
+ client.tui.showToast({ body: { message, variant, duration: 1e4 } }).catch(() => {
31
+ return;
32
+ });
33
+ };
232
34
  log("JfrogOpencodePlugin starting...");
233
- const pullSkillsResponse = await pullSkills($, directory, log);
234
- log("pullSkillsResponse=" + JSON.stringify(pullSkillsResponse));
35
+ let nudgeShown = false;
235
36
  return {
236
37
  config: async (config) => {
237
- config.instructions = config.instructions || [];
238
- if (config.instructions.indexOf(".jfrog/instructions/JFROG-INTEGRATION-MANAGEMENT.md") === -1) {
239
- config.instructions.push(".jfrog/instructions/JFROG-INTEGRATION-MANAGEMENT.md");
240
- log("jfrog integration management added to config");
38
+ const cfg = config;
39
+ cfg.skills = cfg.skills ?? {};
40
+ cfg.skills.paths = cfg.skills.paths ?? [];
41
+ if (!isNonEmptyDir(BUNDLED_SKILLS_DIR)) {
42
+ const message = `JFrog: bundled skills not found at ${BUNDLED_SKILLS_DIR}. ` + "The plugin package may be broken; reinstall @jfrog/opencode-jfrog-plugin.";
43
+ log("ERROR " + message);
44
+ toast(message, "error");
45
+ return;
46
+ }
47
+ if (!cfg.skills.paths.includes(BUNDLED_SKILLS_DIR)) {
48
+ cfg.skills.paths.push(BUNDLED_SKILLS_DIR);
241
49
  }
242
- },
243
- event: async ({ event }) => {
244
- if (event.type === "session.created") {
245
- const sessionId = event.properties.info.id;
246
- const responses = [];
247
- var pkgMngrResponse;
248
- pkgMngrResponse = await setupPackageManagers(client, $, directory, sessionId, log);
249
- if (pkgMngrResponse) {
250
- responses.push(pkgMngrResponse);
251
- }
252
- log("pkgMngrResponse=" + pkgMngrResponse?.message);
253
- if (responses.filter((s) => !s.success).length > 0) {
254
- await client.tui.showToast({
255
- body: {
256
- message: responses.filter((s) => !s.success).map((s) => s.message).join(`
257
-
258
- `),
259
- variant: "error",
260
- duration: 1e4
261
- }
262
- });
263
- }
50
+ log("config.skills.paths=" + JSON.stringify(cfg.skills.paths));
51
+ if (!nudgeShown) {
52
+ nudgeShown = true;
53
+ toast("JFrog: run `jf setup <pm>` to configure package managers against Artifactory.", "info");
264
54
  }
265
55
  }
266
56
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jfrog/opencode-jfrog-plugin",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "JFrog Plugin for seamless integration to Opencode",
5
5
  "author": {
6
6
  "name": "JFrog",
@@ -18,7 +18,8 @@
18
18
  "jfrog",
19
19
  "artifactory",
20
20
  "opencode",
21
- "plugin"
21
+ "plugin",
22
+ "skills"
22
23
  ],
23
24
  "repository": {
24
25
  "type": "git",
@@ -30,12 +31,14 @@
30
31
  },
31
32
  "files": [
32
33
  "dist",
33
- "src/version.ts"
34
+ "skills",
35
+ "sync-skills-vendor.json"
34
36
  ],
35
37
  "main": "dist/index.js",
36
38
  "types": "dist/index.d.ts",
37
39
  "devDependencies": {
38
40
  "@eslint/js": "^9.39.1",
41
+ "@opencode-ai/plugin": "^1.4.6",
39
42
  "@types/node": "^20.11.5",
40
43
  "@typescript-eslint/eslint-plugin": "8.47.0",
41
44
  "@typescript-eslint/parser": "8.47.0",
@@ -46,8 +49,5 @@
46
49
  "prettier": "^3.2.4",
47
50
  "typescript-eslint": "^8.47.0",
48
51
  "vitest": "^3.2.4"
49
- },
50
- "dependencies": {
51
- "@opencode-ai/plugin": "^1.4.6"
52
52
  }
53
53
  }