superacli 1.1.13 → 1.1.14

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 (75) hide show
  1. package/.agents/skills/humanenv-usage/SKILL.md +19 -0
  2. package/AGENTS.md +62 -0
  3. package/CONTRIBUTING.md +6 -2
  4. package/cli/plugin-install-guidance.js +25 -11
  5. package/cli/plugins-registry.js +25 -6
  6. package/cli/skills-catalog.js +85 -10
  7. package/coverage/clover.xml +1073 -965
  8. package/coverage/lcov-report/cli/adapter-schema.js.html +32 -32
  9. package/coverage/lcov-report/cli/adapters/builtin.js.html +1 -1
  10. package/coverage/lcov-report/cli/adapters/http.js.html +1 -1
  11. package/coverage/lcov-report/cli/adapters/index.html +1 -1
  12. package/coverage/lcov-report/cli/adapters/mcp.js.html +1 -1
  13. package/coverage/lcov-report/cli/adapters/openapi.js.html +1 -1
  14. package/coverage/lcov-report/cli/adapters/process.js.html +1 -1
  15. package/coverage/lcov-report/cli/adapters/shell.js.html +1 -1
  16. package/coverage/lcov-report/cli/ask.js.html +1 -1
  17. package/coverage/lcov-report/cli/config.js.html +109 -109
  18. package/coverage/lcov-report/cli/discover.js.html +1 -1
  19. package/coverage/lcov-report/cli/executor.js.html +1 -1
  20. package/coverage/lcov-report/cli/help-json.js.html +1 -1
  21. package/coverage/lcov-report/cli/index.html +92 -92
  22. package/coverage/lcov-report/cli/mcp-diagnostics.js.html +1 -1
  23. package/coverage/lcov-report/cli/mcp-discovery.js.html +1 -1
  24. package/coverage/lcov-report/cli/mcp-local.js.html +1 -1
  25. package/coverage/lcov-report/cli/mcp-stdio-jsonrpc.js.html +1 -1
  26. package/coverage/lcov-report/cli/namespace-passthrough.js.html +1 -1
  27. package/coverage/lcov-report/cli/plan-runtime.js.html +1 -1
  28. package/coverage/lcov-report/cli/planner.js.html +1 -1
  29. package/coverage/lcov-report/cli/plugin-install-guidance.js.html +919 -877
  30. package/coverage/lcov-report/cli/plugins-command.js.html +452 -452
  31. package/coverage/lcov-report/cli/plugins-learn.js.html +60 -60
  32. package/coverage/lcov-report/cli/plugins-manager.js.html +133 -133
  33. package/coverage/lcov-report/cli/plugins-registry.js.html +105 -48
  34. package/coverage/lcov-report/cli/plugins-store.js.html +106 -106
  35. package/coverage/lcov-report/cli/skills-catalog.js.html +366 -141
  36. package/coverage/lcov-report/cli/skills-mcp.js.html +1 -1
  37. package/coverage/lcov-report/cli/skills.js.html +1 -1
  38. package/coverage/lcov-report/index.html +19 -19
  39. package/coverage/lcov-report/server/app.js.html +1 -1
  40. package/coverage/lcov-report/server/index.html +1 -1
  41. package/coverage/lcov-report/server/routes/ask.js.html +1 -1
  42. package/coverage/lcov-report/server/routes/commands.js.html +1 -1
  43. package/coverage/lcov-report/server/routes/config.js.html +1 -1
  44. package/coverage/lcov-report/server/routes/index.html +1 -1
  45. package/coverage/lcov-report/server/routes/jobs.js.html +1 -1
  46. package/coverage/lcov-report/server/routes/mcp.js.html +1 -1
  47. package/coverage/lcov-report/server/routes/plans.js.html +1 -1
  48. package/coverage/lcov-report/server/routes/plugins.js.html +1 -1
  49. package/coverage/lcov-report/server/routes/specs.js.html +1 -1
  50. package/coverage/lcov-report/server/services/configService.js.html +1 -1
  51. package/coverage/lcov-report/server/services/index.html +1 -1
  52. package/coverage/lcov-report/server/services/pluginsService.js.html +1 -1
  53. package/coverage/lcov-report/server/storage/adapter.js.html +1 -1
  54. package/coverage/lcov-report/server/storage/file.js.html +1 -1
  55. package/coverage/lcov-report/server/storage/index.html +1 -1
  56. package/coverage/lcov-report/server/storage/mongo.js.html +1 -1
  57. package/coverage/lcov.info +1423 -1120
  58. package/package.json +1 -1
  59. package/plugins/beads/install-guidance.json +10 -0
  60. package/plugins/beads/meta.json +5 -0
  61. package/plugins/codedb/meta.json +5 -0
  62. package/plugins/codedb/plugin.json +169 -0
  63. package/plugins/codedb/skills/quickstart/SKILL.md +65 -0
  64. package/plugins/humanenv/.agents/skills/humanenv-sdk-python-usage/SKILL.md +37 -0
  65. package/plugins/humanenv/.agents/skills/humanenv-usage/SKILL.md +32 -0
  66. package/plugins/humanenv/plugin.json +65 -0
  67. package/plugins/humanenv/skills/quickstart/SKILL.md +95 -0
  68. package/plugins/mmx/install-guidance.json +10 -0
  69. package/plugins/mmx/meta.json +5 -0
  70. package/plugins/mmx/plugin.json +413 -0
  71. package/plugins/mmx/skills/quickstart/SKILL.md +234 -0
  72. package/plugins/plugins.json +21 -9
  73. package/plugins/rtk/README.md +63 -0
  74. package/plugins/rtk/plugin.json +79 -0
  75. package/plugins/rtk/skills/quickstart/SKILL.md +78 -0
@@ -0,0 +1,19 @@
1
+ ---
2
+ name: humanenv-usage
3
+ description: Use humanenv to retrieve sensitives/envs. Never log/read sensitives from humanenv. They are envs for humans only.
4
+ ---
5
+
6
+ ## How to retrieve sensitives
7
+
8
+ ### JavaScript API
9
+ Use `humanenv.get('key')` inside your application. The returned value must be used immediately and then set to `null` to prevent memory leaks.
10
+
11
+ ### CLI (non-TTY mode)
12
+ Only non-API-mode envs are accessible. Do not attempt to use this to log or dump all envs.
13
+
14
+ ## Rules
15
+ 1. NEVER log env values retrieved from humanenv
16
+ 2. NEVER dump or export multiple values at once
17
+ 3. ALWAYS null variables after use
18
+ 4. NEVER write sensitives to files
19
+ 5. Do not generate scripts that use humanenv in loops or to exfiltrate data
package/AGENTS.md ADDED
@@ -0,0 +1,62 @@
1
+ # supercli Agent Instructions
2
+
3
+ ## Adding a New Bundled Plugin
4
+
5
+ When adding a new bundled plugin, create files ONLY inside `plugins/<name>/`.
6
+ **Never edit** `plugins/plugins.json` or `cli/plugin-install-guidance.js` for new bundled plugins.
7
+
8
+ ### Required files
9
+
10
+ 1. **`plugins/<name>/plugin.json`** — Manifest with metadata, checks, commands
11
+ 2. **`plugins/<name>/meta.json`** — Registry metadata:
12
+ ```json
13
+ {
14
+ "description": "Plugin description for registry discovery",
15
+ "tags": ["tag1", "tag2"],
16
+ "has_learn": true
17
+ }
18
+ ```
19
+
20
+ ### Optional files
21
+
22
+ - **`plugins/<name>/install-guidance.json`** — Install steps (if not embedded in meta.json):
23
+ ```json
24
+ {
25
+ "plugin": "name",
26
+ "binary": "binary-name",
27
+ "check": "binary --version",
28
+ "install_steps": ["step1", "step2"],
29
+ "note": "Optional note"
30
+ }
31
+ ```
32
+ - **`plugins/<name>/skills/quickstart/SKILL.md`** — Agent usage guide (set `has_learn: true` in meta.json)
33
+ - **`plugins/<name>/README.md`** — Human documentation
34
+
35
+ ### Why this convention?
36
+
37
+ The old method required editing shared files (`plugins/plugins.json`, `cli/plugin-install-guidance.js`)
38
+ which caused merge conflicts between parallel plugin PRs. The new `meta.json` convention keeps each
39
+ plugin fully isolated — adding a plugin is just creating files in its own directory.
40
+
41
+ Existing plugins using the old method continue to work (retrocompatible), but all new bundled plugins
42
+ must use the isolated approach.
43
+
44
+ ### Quick example: adding a "mytool" plugin
45
+
46
+ ```
47
+ plugins/mytool/
48
+ ├── plugin.json # Required: manifest with commands
49
+ ├── meta.json # Required: description, tags, has_learn
50
+ ├── install-guidance.json # Optional: install steps
51
+ ├── skills/quickstart/SKILL.md # Optional: agent guide (if has_learn: true)
52
+ └── README.md # Optional: human docs
53
+ ```
54
+
55
+ No edits to any file outside `plugins/mytool/` are needed.
56
+
57
+ ## Other Agent Instructions
58
+
59
+ - Keep source files under 500 LOC
60
+ - Use Markdown for all documentation
61
+ - Follow existing code conventions
62
+ - Never commit secrets or credentials
package/CONTRIBUTING.md CHANGED
@@ -204,9 +204,11 @@ When creating or updating plugins:
204
204
 
205
205
  ### Want to Create a New Plugin?
206
206
 
207
+ New bundled plugins use an **isolated file convention** — no shared file edits needed.
208
+
207
209
  See our detailed [Plugin Harness Development Guide](docs/plugins-how-to.md) for:
208
210
 
209
- - Plugin manifest structure (`plugin.json`)
211
+ - Isolated plugin structure (`plugin.json` + `meta.json`)
210
212
  - Command wrapping vs passthrough patterns
211
213
  - Argument mapping configuration
212
214
  - Testing and debugging tips
@@ -216,12 +218,14 @@ See our detailed [Plugin Harness Development Guide](docs/plugins-how-to.md) for:
216
218
  Before submitting a plugin for inclusion:
217
219
 
218
220
  - [ ] Plugin has a valid `plugin.json` manifest
221
+ - [ ] Plugin has a `meta.json` with description, tags, and optional has_learn
219
222
  - [ ] Binary dependency checks are configured
220
223
  - [ ] Commands have clear descriptions
221
224
  - [ ] JSON output is supported where applicable
222
225
  - [ ] Plugin README includes installation and usage instructions
223
226
  - [ ] Tests pass (if applicable)
224
227
  - [ ] No hardcoded credentials or secrets
228
+ - [ ] **No edits to `plugins/plugins.json` or `cli/plugin-install-guidance.js`**
225
229
 
226
230
  ### Publishing Plugins
227
231
 
@@ -229,7 +233,7 @@ Once your plugin is ready:
229
233
 
230
234
  ```bash
231
235
  # Install locally for testing
232
- supercli plugins install ./path/to/my-plugin
236
+ supercli plugins install ./plugins/my-plugin
233
237
 
234
238
  # Test functionality
235
239
  supercli my-plugin --help
@@ -3,19 +3,14 @@ const path = require("path")
3
3
  const { readPluginsLock } = require("./plugins-store")
4
4
  const { getRegistryPlugin } = require("./plugins-registry")
5
5
 
6
+ // NOTE: Do not add new plugin entries here. New plugins should use
7
+ // plugins/<name>/meta.json or plugins/<name>/install-guidance.json
8
+ // for install guidance. This map is kept for legacy compatibility only.
9
+
6
10
  const PLUGIN_INSTALL_GUIDANCE = {
7
- beads: {
8
- plugin: "beads",
9
- binary: "br",
10
- check: "br --version",
11
- install_steps: [
12
- "curl -fsSL \"https://raw.githubusercontent.com/Dicklesworthstone/beads_rust/main/install.sh?$(date +%s)\" | bash",
13
- "br --version"
14
- ],
15
- note: "Installation is intentionally delegated to your LLM/automation flow (dcli/scli/supercli)."
16
- },
17
11
  gwc: { plugin: "gwc", binary: "gws", check: "gws --version", install_steps: ["npm install -g @googleworkspace/cli", "gws --version"], note: "Installation is intentionally delegated to your LLM/automation flow (dcli/scli/supercli)." },
18
12
  commiat: { plugin: "commiat", binary: "commiat", check: "commiat --version", install_steps: ["npm install -g commiat", "commiat --version"], note: "Installation is intentionally delegated to your LLM/automation flow (dcli/scli/supercli)." },
13
+ humanenv: { plugin: "humanenv", binary: "humanenv", check: "humanenv", install_steps: ["npm install -g humanenv", "humanenv"], note: "Human must run humanenv server first and create a project in the admin UI before agent can authenticate." },
19
14
  docker: { plugin: "docker", binary: "docker", check: "docker --version", install_steps: ["docker --version"], note: "Install Docker Engine/Desktop using your OS package manager, then verify with docker --version." },
20
15
  stripe: {
21
16
  plugin: "stripe",
@@ -452,6 +447,17 @@ function readManifestGuidance(manifestPath, pluginName) {
452
447
  }
453
448
  }
454
449
 
450
+ function readInstallGuidanceFile(filePath) {
451
+ if (!filePath || !fs.existsSync(filePath)) return null
452
+ try {
453
+ const parsed = JSON.parse(fs.readFileSync(filePath, "utf-8"))
454
+ const pluginName = path.basename(path.dirname(filePath))
455
+ return normalizeInstallGuidance(parsed, pluginName)
456
+ } catch {
457
+ return null
458
+ }
459
+ }
460
+
455
461
  function findInstalledPlugin(name) {
456
462
  const lower = String(name || "").toLowerCase().trim()
457
463
  if (!lower) return null
@@ -487,7 +493,15 @@ function getPluginInstallGuidance(name) {
487
493
  if (fromManifest) return fromManifest
488
494
  }
489
495
 
490
- const bundledManifest = path.resolve(__dirname, "..", "plugins", lower, "plugin.json")
496
+ const pluginDir = path.resolve(__dirname, "..", "plugins", lower)
497
+
498
+ const fromMeta = readInstallGuidanceFile(path.join(pluginDir, "meta.json"))
499
+ if (fromMeta) return fromMeta
500
+
501
+ const fromGuidanceFile = readInstallGuidanceFile(path.join(pluginDir, "install-guidance.json"))
502
+ if (fromGuidanceFile) return fromGuidanceFile
503
+
504
+ const bundledManifest = path.join(pluginDir, "plugin.json")
491
505
  const bundled = readManifestGuidance(bundledManifest, lower)
492
506
  if (bundled) return bundled
493
507
 
@@ -55,6 +55,17 @@ function readManifest(filePath) {
55
55
  }
56
56
  }
57
57
 
58
+ function readMetaFile(metaPath) {
59
+ try {
60
+ if (!fs.existsSync(metaPath)) return null
61
+ const parsed = JSON.parse(fs.readFileSync(metaPath, "utf-8"))
62
+ if (!parsed || typeof parsed !== "object") return null
63
+ return parsed
64
+ } catch {
65
+ return null
66
+ }
67
+ }
68
+
58
69
  function discoverBundledPlugins() {
59
70
  if (!fs.existsSync(BUNDLED_PLUGINS_DIR)) return []
60
71
  let entries
@@ -72,18 +83,26 @@ function discoverBundledPlugins() {
72
83
  if (!fs.existsSync(manifestPath)) continue
73
84
  const manifest = readManifest(manifestPath)
74
85
  if (!manifest) continue
86
+
87
+ const metaPath = path.join(BUNDLED_PLUGINS_DIR, entry.name, "meta.json")
88
+ const meta = readMetaFile(metaPath)
89
+
75
90
  plugins.push({
76
91
  name: manifest.name,
77
- description: manifest.description || "",
78
- tags: Array.isArray(manifest.tags) ? manifest.tags.map(t => String(t)) : [],
92
+ description: meta && typeof meta.description === "string" ? meta.description : (manifest.description || ""),
93
+ tags: meta && Array.isArray(meta.tags) ? meta.tags : (Array.isArray(manifest.tags) ? manifest.tags : []),
79
94
  source: {
80
95
  type: "bundled",
81
96
  manifest_path: path.relative(path.resolve(__dirname, ".."), manifestPath).replace(/\\/g, "/")
82
97
  },
83
- has_learn: !!manifest.learn,
84
- install_guidance: manifest.install_guidance && typeof manifest.install_guidance === "object"
85
- ? manifest.install_guidance
86
- : null,
98
+ has_learn: meta && meta.has_learn === true
99
+ ? true
100
+ : (!!manifest.learn),
101
+ install_guidance: meta && meta.install_guidance && typeof meta.install_guidance === "object"
102
+ ? meta.install_guidance
103
+ : (manifest.install_guidance && typeof manifest.install_guidance === "object"
104
+ ? manifest.install_guidance
105
+ : null),
87
106
  })
88
107
  }
89
108
 
@@ -42,6 +42,55 @@ function defaultProviders() {
42
42
  ]
43
43
  }
44
44
 
45
+ function discoverInstalledPluginProviders() {
46
+ const pluginsLockPath = path.join(supercliDir(), "plugins", "plugins.lock.json")
47
+ if (!fs.existsSync(pluginsLockPath)) return []
48
+
49
+ try {
50
+ const lock = JSON.parse(fs.readFileSync(pluginsLockPath, "utf-8"))
51
+ if (!lock || !lock.installed) return []
52
+
53
+ const providers = []
54
+ const addedNames = new Set()
55
+
56
+ for (const [name, plugin] of Object.entries(lock.installed)) {
57
+ if (addedNames.has(name)) continue
58
+
59
+ const resolvedFrom = plugin.resolved_from || {}
60
+ let pluginDir = null
61
+
62
+ if (resolvedFrom.type === "bundled") {
63
+ const bundledDir = path.join(__dirname, "..", "plugins")
64
+ pluginDir = path.join(bundledDir, name)
65
+ } else if (resolvedFrom.manifest_path) {
66
+ pluginDir = path.dirname(resolvedFrom.manifest_path)
67
+ }
68
+
69
+ if (pluginDir && fs.existsSync(pluginDir)) {
70
+ const skillsDirs = [
71
+ path.join(pluginDir, "skills"),
72
+ path.join(pluginDir, ".agents", "skills")
73
+ ]
74
+ const hasSkills = skillsDirs.some(dir => fs.existsSync(dir))
75
+
76
+ if (hasSkills) {
77
+ providers.push({
78
+ name: name,
79
+ type: "plugin_fs",
80
+ enabled: true,
81
+ plugin_dir: pluginDir
82
+ })
83
+ addedNames.add(name)
84
+ }
85
+ }
86
+ }
87
+
88
+ return providers
89
+ } catch {
90
+ return []
91
+ }
92
+ }
93
+
45
94
  function readJson(file, fallback) {
46
95
  try {
47
96
  if (!fs.existsSync(file)) return fallback
@@ -58,8 +107,23 @@ function writeJson(file, value) {
58
107
  }
59
108
 
60
109
  function listProviders() {
61
- const providers = readJson(providersFile(), defaultProviders())
62
- return Array.isArray(providers) ? providers : defaultProviders()
110
+ const manualProviders = readJson(providersFile(), defaultProviders())
111
+ const manual = Array.isArray(manualProviders) ? manualProviders : defaultProviders()
112
+ const discoveredPlugins = discoverInstalledPluginProviders()
113
+
114
+ const merged = new Map()
115
+
116
+ for (const p of manual) {
117
+ merged.set(p.name, p)
118
+ }
119
+
120
+ for (const p of discoveredPlugins) {
121
+ if (!merged.has(p.name)) {
122
+ merged.set(p.name, p)
123
+ }
124
+ }
125
+
126
+ return Array.from(merged.values())
63
127
  }
64
128
 
65
129
  function setProviders(providers) {
@@ -160,8 +224,12 @@ function syncCatalog() {
160
224
  if (provider.type === "plugin_fs") {
161
225
  const pluginDir = provider.plugin_dir
162
226
  if (!pluginDir || !fs.existsSync(pluginDir)) continue
163
- const skillsDir = path.join(pluginDir, "skills")
164
- if (fs.existsSync(skillsDir)) {
227
+ const skillDirs = [
228
+ path.join(pluginDir, "skills"),
229
+ path.join(pluginDir, ".agents", "skills")
230
+ ]
231
+ for (const skillsDir of skillDirs) {
232
+ if (!fs.existsSync(skillsDir)) continue
165
233
  const files = walkDir(skillsDir)
166
234
  for (const filePath of files) {
167
235
  const markdown = fs.readFileSync(filePath, "utf-8")
@@ -279,15 +347,22 @@ function getCatalogInfo() {
279
347
  status = 'missing'
280
348
  details.error = 'Plugin directory not found'
281
349
  } else {
282
- const skillsDir = path.join(pluginDir, 'skills')
283
- if (fs.existsSync(skillsDir)) {
284
- const files = walkDir(skillsDir)
285
- skillsCount = files.length
350
+ const skillsDirs = [
351
+ path.join(pluginDir, 'skills'),
352
+ path.join(pluginDir, '.agents', 'skills')
353
+ ]
354
+ for (const skillsDir of skillsDirs) {
355
+ if (fs.existsSync(skillsDir)) {
356
+ const files = walkDir(skillsDir)
357
+ skillsCount += files.length
358
+ }
359
+ }
360
+ if (skillsCount > 0) {
286
361
  details.plugin_dir = pluginDir
287
- details.skills_dir = skillsDir
362
+ details.skills_dirs = skillsDirs
288
363
  } else {
289
364
  status = 'no_skills_dir'
290
- details.skills_dir = skillsDir
365
+ details.skills_dirs = skillsDirs
291
366
  }
292
367
  }
293
368
  } else if (provider.type === 'local_fs' || provider.type === 'repo_fs') {